디자인 패턴에 대해 읽고 있었고 프로토 타입 디자인 패턴이 과도한 서브 클래 싱으로 사라 졌다는 것을 읽었습니다.
서브 클래 싱이 왜 나쁜가요? 프로토 타입을 사용하면 서브 클래 싱보다 어떤 이점이 있습니까?
디자인 패턴에 대해 읽고 있었고 프로토 타입 디자인 패턴이 과도한 서브 클래 싱으로 사라 졌다는 것을 읽었습니다.
서브 클래 싱이 왜 나쁜가요? 프로토 타입을 사용하면 서브 클래 싱보다 어떤 이점이 있습니까?
답변:
서브 클래 싱이 너무 나쁜 이유
"너무 많이"는 판단 요청입니다. 하지만 나에게서 가져가는 것은 나쁘다. 내가 작업하는 코드에는 DEEP 상속이 있으며 코드는 읽기, 이해, 추적, 추적, 디버그 등이 어렵습니다.이 물건에 대한 테스트 코드를 작성하는 것은 사실상 불가능합니다.
프로토 타입 패턴은 서브 클래 싱을 없애줍니다.
또는이 질문은 "너무 많은 서브 클래 싱을 없앨까요?"라는 의미입니까? 이 패턴은 적어도 그 시점에서 서브 클래 싱을 피하기 위해 "템플릿"객체를 복제해야합니다. "템플릿"이 하위 클래스가 될 수 없다는 규칙은 없습니다.
상속보다 구성 선호
이 아이디어에는 위임 및 집계도 포함됩니다. 이 휴리스틱을 따르면 소프트웨어가보다 유연하고 유지 관리, 확장 및 재사용이 더 쉬워지는 경향이 있습니다.
클래스가 파트로 구성되면 런타임에 해당 파트를 대체 할 수 있습니다 . 이것은 테스트 가능성에 큰 영향을 미칩니다.
테스트가 더 쉽습니다 . 가짜 부분 (예 : "mocks", "doubles"및 기타 테스트 대화)을 사용할 수 있습니다. 코드의 깊은 상속은 모든 계층을 인스턴스화하여 비트를 테스트해야 함을 의미합니다. 우리의 경우 실제 환경에서 코드를 실행하지 않으면 불가능합니다. 예를 들어 비즈니스 객체를 인스턴스화하려면 데이터베이스가 필요합니다.
부작용과 불확실성에 변화가 생긴다 .-클래스가 "기본"일수록 효과의 폭이 넓어진 다. 부작용 불확실성으로 인해 감히 변경하지 않은 원하는 변경 사항이있을 수 있습니다. 또는 우리의 상속 체인의 어떤 곳에 좋은 변화는 다른 것에 좋지 않습니다. 이것은 확실히 내 경험입니다.
두 가지 이유가 있습니다.
런타임 성능입니다. 수퍼 클래스에서 서브 클래스를 호출 할 때마다 메소드 호출을 수행하므로 5 개의 클래스를 중첩하고 기본 클래스에서 메소드를 호출하면 5 개의 메소드 호출이 수행됩니다. 대부분의 컴파일러 / 런타임은이를 인식하고 추가 호출을 최적화하려고 시도하지만 매우 간단한 경우에만이를 수행하는 것이 안전합니다.
동료 프로그래머의 정신입니다. 5 개의 클래스를 중첩하면 기본 클래스에서 메소드를 실제로 호출하는지 확인하기 위해 4 개의 상위 클래스를 모두 검사해야합니다. 또한 프로그램을 디버깅 할 때 5 가지 메서드 호출을 수행해야 할 수도 있습니다.
"너무 많이"는 판단 요청입니다.
프로그래밍에서 대부분의 것들과 마찬가지로 서브 클래 싱은 본질적으로 나쁘지 않습니다 . 문제 해결 모델이 부품 구성이 아닌 계층 구조로 이해되는 경우 서브 클래 싱이 선호되는 옵션 일 수 있습니다.
즉, 상속보다 구성을 선호하는 것이 좋은 경험입니다.
서브 클래스를 만들 때, radarbob이 지적했듯이 테스트가 더 어려울 수 있습니다 . 깊은 계층 구조에서는 하위 클래스를 인스턴스화하려면 전체 수퍼 클래스 계층 구조와 추가 코드를 가져와야하므로 문제가있는 코드를 격리하기가 더 어렵습니다. 구성 방식을 사용하면 단위 테스트, 모의 객체 등으로 집계 객체의 각 구성 요소를 분리하고 테스트 할 수 있습니다.
서브 클래 싱을 사용하면 원하지 않는 구현 세부 정보를 노출시킬 수도 있습니다. 이 어려운 데이터의 기본 표현에 대한 액세스를 제어 할 수 있습니다 그리고 그것은 당신의 백업 모델의 특정 구현에 당신을 묶어.
내가 생각할 수있는 한 가지 예는 java.util.Properties이며 Hashtable에서 상속됩니다. Properties 클래스는 문자열-문자열 쌍만 저장하기위한 것입니다 (Javadocs에 명시되어 있음). 상속으로 인해 Hashtable의 put 및 putAll 메소드가 Properties 사용자에게 노출되었습니다. 속성을 저장하는 "올바른"방법은 setProperty ()를 사용하는 반면, 사용자가 put ()을 호출하고 String 및 Object를 전달하는 것을 막을 수있는 것은 없습니다.
기본적으로 속성의 의미는 상속으로 인해 잘못 정의되어 있습니다. 또한 누구나 속성에 대한 지원 개체를 변경하려는 경우 속성이보다 구성 방식을 사용하는 경우보다 속성을 사용하는 코드에 미치는 영향이 훨씬 큽니다.
상속은 경우에 따라 캡슐화 를 깨뜨릴 수 있으며 , 이러한 경우 캡슐화 가 나빠질 수 있습니다. 자세한 내용을 읽으십시오.
상속받지 않은 좋은 옛날 도서관은 API를 사용하여 API와 애플리케이션을 공개하여 공개적으로 볼 수 있는 것을 사용하며 이제 라이브러리는 앱을 손상시키지 않고 계속 변경되는 내부 기어를 처리하는 자체 방법이 있습니다.
요구가 발전함에 따라 도서관은 발전 할 수 있으며 더 많은 고객을 확보 할 수 있습니다. 또는 다른 풍미로 자체 클래스에서 상속하여 확장 기능을 제공 할 수 있습니다. 여태까지는 그런대로 잘됐다.
그러나 근본적인 점은 응용 프로그램이 클래스를 가져 와서 서브 클래스 화하기 시작하면 이제 서브 클래스는 실제로 내부 파트너가 아닌 클라이언트 입니다. 그러나 퍼블릭 API를 정의하는 명확한 방법과 달리 서브 클래스는 라이브러리 내부에서 훨씬 더 깊습니다 (모든 개인 변수에 대한 액세스 등). 아직 나쁘지는 않지만 불쾌한 캐릭터는 라이브러리뿐만 아니라 APP 내부에 너무 많은 API를 연결할 수 있습니다.
본질적으로 이것이 항상 그런 것은 아니지만,
상속을 잘못 사용하여 캡슐화를 깨뜨리기 쉽습니다.
이 시점에서 서브 클래 싱 허용이 잘못 될 수 있습니다.
짧은 빠른 답변 :
그것은 당신이하는 일에 달려 있습니다.
확장 된 보링 답변 :
개발자는 앱을 만들 수 있습니다. 서브 클래 싱 또는 (프로토 타입) 템플릿을 사용합니다. 때로는 하나의 기술이 더 잘 작동합니다. 때로는 다른 기술이 더 잘 작동합니다.
"다중 상속"시나리오가 존재하는지 고려하는 기술을 선택하는 것이 가장 효과적입니다. 프로그래밍 언어가 단일 상속, 템플릿 또는 프로토 타입 만 지원하는 경우에도 마찬가지입니다.
보충 참고 사항 :
일부 답변은 "다중 상속"과 관련이 있습니다. 주된 질문이 아니라 변경, 주제와 관련이 있습니다. "다중 상속 대 구성"에 대한 몇 가지 유사한 게시물이 있습니다. 나는 둘 다 섞는 경우가 있었다.