답변:
실제로 상속을 사용하는 것이 차선책이라는 사실이 점점 더 많이 발견됩니다.
구현 상속은 항상 인터페이스 상속과 컴포지션으로 대체 될 수 있으며,보다 현대적인 소프트웨어 디자인은 컴포지션에 유리하게 상속을 사용하는 방향으로 가고 있습니다.
그래서 예 , 특히 상속을 제공하지 않는 것은 완전히 유효하고, 매우이다 의 유행 디자인 결정.
유지 mixin, 다른 한편으로는,도 (아직) 주류 언어 기능하지 않고, 언어 않는다 "믹스 인"기능을 제공 종종에 의해 매우 다른 것을 이해합니다. 부담없이 제공하십시오. 개인적으로 나는 그것이 매우 유용하다고 생각하지만 올바르게 구현하는 것은 매우 어려울 수 있습니다.
언어의 나머지 의미를 고려하지 않고 상속 (또는 실제로 하나의 기능)이 필요한지 아닌지에 대한 추론은 의미가 없습니다. 당신은 진공 상태에서 주장하고 있습니다.
필요한 것은 일관된 언어 디자인 철학입니다. 언어는 의도 된 문제를 우아하게 해결할 수 있어야합니다. 이것을 달성하기위한 모델은 상속을 요구하거나 요구하지 않을 수 있지만, 큰 그림이 없다면 이것을 판단하기는 어렵다.
예를 들어, 언어에 일급 함수, 부분 함수 응용 프로그램, 다형성 데이터 형식, 형식 변수 및 제네릭 형식이있는 경우 기존 OOP 상속에서와 동일한 기반을 사용하지만 다른 패러다임을 사용합니다.
늦은 바인딩, 동적 타이핑, 속성으로서의 메소드, 유연한 함수 인수 및 최고급 함수가있는 경우에도 동일한 패러다임을 사용하여 동일한 근거를 다룹니다.
(개요 된 두 가지 패러다임의 예를 읽는 것은 독자를위한 연습으로 남겨둔다.)
그래서 당신이 원하는 의미론에 대해 생각하고, 그것들을 가지고 놀며 상속없이 충분한 지 확인하십시오. 그렇지 않은 경우, 상속에 믹스를 던지거나 다른 것이 누락되었다고 결정할 수 있습니다.
예.
특히 언어가 동적으로 입력되는 경우 상속을 허용하지 않는 것이 좋습니다. 예를 들어 위임 또는 구성을 통해 유사한 코드 재사용을 달성 할 수 있습니다. 예를 들어, 좀 적당히 복잡한 프로그램을 작성했습니다 - 좋아,하지 것을 복잡 :) - 자바 스크립트의 모든 상속하지 않고. 기본적으로 객체를 대수 데이터 구조로 사용하여 일부 함수를 메소드로 첨부했습니다. 또한 이러한 객체에서 작동하는 방법 이 아닌 많은 기능이있었습니다 .
동적 타이핑을 사용하고 있고 가정한다면 상속없이 다형성을 가질 수 있습니다. 또한 런타임에 객체에 임의의 메소드를 추가하도록 허용하면 실제로 믹스 인과 같은 것이 필요하지 않습니다.
좋은 옵션이라고 생각되는 또 다른 옵션은 JavaScript를 에뮬레이트하고 프로토 타입을 사용하는 것입니다. 이것들은 클래스보다 간단하지만 매우 유연합니다. 고려해야 할 것.
그래서 모든 사람들이 말했습니다.
예, 상속을 생략하는 것은 완전히 합리적인 디자인 결정입니다.
실제로 구현 상속을 제거해야하는 매우 좋은 이유가 있습니다. 코드를 작성하기가 매우 복잡하고 유지하기가 어렵 기 때문입니다. 상속 (일반적으로 대부분의 OOP 언어로 구현 됨)을 잘못된 것으로 간주하기까지합니다.
예를 들어 Clojure는 구현 상속을 제공하지 않으며 동일한 결과를 훨씬 더 명확하게 달성하는 데 사용할 수있는 일련의 직교 기능 (프로토콜, 데이터, 함수, 매크로)을 제공하는 것을 선호합니다.
Rich Hickey가 프로그래밍 언어의 복잡한 복잡성 (상속 포함)을 식별하고 각각에 대한 대안을 제시하는이 일반적인 주제에 대해 매우 깨달은 비디오가 있습니다.
VB6 클래스가 상속을 지원하지 않는다는 사실 (인터페이스 만)을 처음 접했을 때 실제로 저를 화나게했습니다.
그러나 그렇게 나쁜 이유 는 생성자 매개 변수가 없기 때문에 정상적인 종속성 주입 (DI)을 수행 할 수 없었기 때문입니다. DI를 가지고 있다면 상속보다 구성을 선호하는 원칙을 따를 수 있기 때문에 상속보다 중요합니다. 어쨌든 코드를 재사용하는 더 좋은 방법입니다.
그래도 믹스 인이 없습니까? 인터페이스를 구현하고 해당 인터페이스의 모든 작업을 종속성 주입을 통해 객체 세트에 위임하려면 Mixins가 이상적입니다. 그렇지 않으면 모든 메소드 및 / 또는 속성을 자식 객체에 위임하기 위해 모든 상용구 코드를 작성해야합니다. 나는 그것을 많이한다 (C # 덕분에) 그리고 내가 할 필요가없는 한 가지 일이다.
다른 답변에 동의하지 않으려면 : 아니요, 더 원하는 기능과 호환되지 않는 기능은 버립니다. Java (및 기타 GC 언어)는 유형 안전성을 원했기 때문에 명시 적 메모리 관리를 중단했습니다. 하스켈은 방정식 추론과 공상 유형을 더 원했기 때문에 돌연변이를 버렸다. C조차도 컴파일러 최적화를 더 원했기 때문에 특정 종류의 앨리어싱 및 기타 동작을 버렸습니다 (또는 불법으로 선언).
질문은 상속보다 무엇을 원하십니까?
free
/ delete
동작은 당신에게 무효화 참조 할 수있는 기능을 제공합니다; 유형 시스템이 영향을받는 모든 참조를 추적 할 수 없으면 언어가 안전하지 않습니다. 특히 C 나 C ++은 모두 타입이 안전하지 않습니다. 동의하도록 서로간에 타협 할 수있는 것은 사실입니다 (예 : 선형 유형 또는 할당 제한). 정확히 말하면 Java가 특정 단순 유형 시스템과 무제한 할당을 통해 유형 안전 을 원한다고 말 했어야합니다 .
null
참조). 금지 free
는 상당히 임의의 추가 제한 사항입니다. 요약하면, 언어가 안전한 유형인지 여부는 언어보다는 유형 안전에 대한 정의에 더 의존합니다.
T
참조는 null
클래스 확장 중 하나 또는 객체를 나타냅니다 T
. null
추악하지만 null
위의 불변 유형을 손상시키지 않고 잘 정의 된 예외를 처리하는 작업이 발생합니다. C ++와 대비 :를 호출 후 delete
하는 T*
포인터는 더 이상은 보유하는 메모리를 가리 수 없다 T
개체를. 더 나쁜 것은 할당에서 해당 포인터를 사용하여 필드 할당을 수행하는 경우 다른 클래스의 객체 필드가 근처 주소에 배치 된 경우 완전히 업데이트 할 수 있습니다. 그것은 용어의 유용한 정의에 의한 유형 안전이 아닙니다.
아니.
기본 언어 기능을 제거하려면 해당 기능이 결코 필요하지 않다는 것을 보편적으로 선언하고 있습니다 (또는 여기에 적용되지 않는 구현하기에는 부적합합니다). 그리고 "never"는 소프트웨어 엔지니어링에서 강력한 단어입니다. 그러한 진술을하려면 매우 강력한 근거가 필요합니다.
엄격하게 C ++ 관점에서 말하면 상속은 두 가지 주요 목적에 유용합니다.
너무 많은 곡예에 빠지지 않고 코드를 공유 할 수있는 방법이 있다면 포인트 1의 경우 상속을 피할 수 있습니다. 포인트 2의 경우 자바 방식으로 가서이 기능을 구현하기 위해 인터페이스를 요구할 수 있습니다.
상속 제거의 이점은
이러한 상충 관계는 대개 "반복하지 말 것"과 한쪽의 유연성과 다른 쪽의 문제 방지 사이에 있습니다. 개인적으로 나는 C ++에서 상속이 단순히 다른 개발자가 문제를 볼만큼 똑똑하지 않을 수 있기 때문에 싫어하는 것을 싫어합니다.
상속이나 믹스 인을 허용하지 않는 것이 좋다고 생각합니까? (사용자가 최소한 인터페이스를 갖도록 주어진 경우)
구현 상속이나 믹스 인 없이 많은 유용한 작업을 수행 할 수 있지만 객체가 인터페이스 A를 구현하면 B 인터페이스 (예 : A는 B를 전문으로하므로 유형 관계가 있습니다. 반면에 결과 객체는 두 인터페이스를 모두 구현한다는 기록 만 있으면되므로 복잡성이 그리 크지 않습니다. 모두 완벽하게 할 수 있습니다.
구현 상속이 부족하다는 한 가지 단점이 있습니다. 클래스에 대해 숫자 인덱스 vtable을 생성 할 수 없으므로 모든 메소드 호출에 대해 해시 조회를 수행해야합니다 (또는 피할 수있는 영리한 방법을 찾아야 함). 이 메커니즘을 통해 기본 값 (예 : 숫자)까지 라우팅하는 경우이 작업이 어려울 수 있습니다. 모든 내부 루프에서 여러 번 적중하면 아주 좋은 해시 구현조차도 비쌀 수 있습니다!