Java는 언어를 단순하게 유지하려는 디자인 목표를 없애기 위해 여러 상속을 생략 합니다 .
Java (에코 시스템 포함)가 실제로 "단순"한지 궁금합니다. 파이썬은 복잡하지 않으며 여러 상속이 있습니다. 그래서 너무 주관적이지 않으면 서 제 질문은 ...
다중 상속을 많이 사용하도록 설계된 코드에서 이점을 얻는 일반적인 문제 패턴은 무엇입니까?
Java는 언어를 단순하게 유지하려는 디자인 목표를 없애기 위해 여러 상속을 생략 합니다 .
Java (에코 시스템 포함)가 실제로 "단순"한지 궁금합니다. 파이썬은 복잡하지 않으며 여러 상속이 있습니다. 그래서 너무 주관적이지 않으면 서 제 질문은 ...
다중 상속을 많이 사용하도록 설계된 코드에서 이점을 얻는 일반적인 문제 패턴은 무엇입니까?
답변:
찬성 :
단점 :
C ++에서 직교 피처를 합성하는 데 사용되는 다중 상속의 좋은 예는 CRTP 를 사용 하여 예를 들어 게임의 구성 요소 시스템을 설정하는 경우입니다.
예제를 작성하기 시작했지만 실제 예제가 더 가치가 있다고 생각합니다. Ogre3D의 일부 코드는 훌륭하고 직관적 인 방식으로 다중 상속을 사용합니다. 예를 들어, Mesh 클래스는 Resources와 AnimationContainer에서 상속받습니다. 리소스는 모든 리소스에 공통 인 인터페이스를 노출하고 AnimationContainer는 애니메이션 세트를 조작하기위한 인터페이스를 노출합니다. 그것들은 관련이 없으므로 메쉬를 애니메이션 세트를 포함 할 수있는 리소스로 생각하기 쉽습니다. 자연스럽지 않습니까?
이 라이브러리 에서 다른 예제를 살펴볼 수 있습니다 . 클래스가 새로운 CRTP 클래스 오버로드를 새로 작성하여 삭제 함으로써 메모리 할당이 세분화 된 방식으로 관리되는 방식 과 같습니다 .
앞서 언급했듯이 다중 상속의 주요 문제는 관련 개념을 혼합하여 발생합니다. 언어가 복잡한 구현을 설정해야하고 (C ++이 다이아몬드 문제를 해결할 수있는 방법을 참조하십시오 ...) 사용자는 해당 구현에서 무슨 일이 일어나고 있는지 확신하지 못합니다. 예를 들어, C ++에서 구현되는 방법을 설명하는이 기사를 읽으십시오 .
언어에서 언어를 제거하면 언어가 어떻게 나쁜지를 강요하는지 모르는 사람들을 피할 수 있습니다. 그러나 때로는 자연스럽게 느껴지지 않는 방식으로 생각해야합니다. 심지어 경우에도 당신이 생각할 수있는 더 자주 발생합니다.
나는 여기서 많이 탐구하지는 않지만 다음 링크 http://docs.python.org/release/1.5.1p1/tut/multiple.html을 통해 파이썬의 다중 상속을 확실히 이해할 수 있습니다 .
의미를 설명하는 데 필요한 유일한 규칙은 클래스 속성 참조에 사용되는 해결 규칙입니다. 이것은 깊이 우선, 왼쪽에서 오른쪽입니다. 따라서, DerivedClassName에서 속성을 찾을 수없는 경우 Base1에서 속성을 검색 한 다음 Base1의 기본 클래스에서 (반복적으로) 속성을 찾을 수없는 경우에만 Base2에서 검색합니다.
...
우연한 이름 충돌을 피하기위한 규칙에 대한 파이썬의 의존을 고려할 때 다중 상속의 무차별 사용은 유지 보수의 악몽이라는 것이 분명합니다. 다중 상속에서 잘 알려진 문제는 공통 기본 클래스를 갖는 두 클래스에서 파생 된 클래스입니다. 이 경우에 발생하는 상황 (인스턴스 변수의 단일 사본 또는 공통 기본 클래스에서 사용하는 데이터 속성이 있음)을 파악하기는 쉽지만 이러한 의미가 어떤 식 으로든 확실하지 않습니다. 유능한.
이것은 단지 작은 단락이지만 추측 한 의심을 없애기에 충분합니다.
다중 상속이 유용한 한 곳은 클래스가 여러 인터페이스를 구현하는 상황이지만 각 인터페이스에 기본 기능이 내장되어 있어야합니다. 이것은 일부 인터페이스를 구현하는 대부분의 클래스가 동일한 방식으로 무언가를 원하지만 때로는 다른 것을해야하는 경우에 유용합니다. 각 클래스를 동일한 구현으로 가질 수 있지만 한 위치로 밀어 넣는 것이 더 합리적입니다.
다중 상속을 많이 사용하도록 설계된 코드에서 이점을 얻는 일반적인 문제 패턴은 무엇입니까?
이것은 단지 하나의 예일뿐입니다. 그러나 안전을 개선하고 호출자 또는 하위 클래스 전체에 걸쳐 계단식 변경 사항을 적용하려는 유혹을 완화하는 데 귀중한 것으로 나타났습니다.
가장 추상적 인 경우에도 다중 상속이 매우 유용하다는 것을 알았을 때 상태 비 저장 인터페이스는 C ++의 비가 상 인터페이스 관용구 (NVI)입니다.
그들은 계약의 보편적 측면을 강제하기 위해 약간의 구현을 가진 인터페이스 와 같이 기본 클래스를 실제로 추상화 하지도 않습니다. .
간단한 예 (일부 전달 된 파일 핸들이 열려 있는지 또는 이와 비슷한 지 확인할 수 있음) :
// Non-virtual interface (public methods are nonvirtual/final).
// Since these are modeling the concept of "interface", not ABC,
// multiple will often be inherited ("implemented") by a subclass.
class SomeInterface
{
public:
// Pre: x should always be greater than or equal to zero.
void f(int x) /*final*/
{
// Make sure x is actually greater than or equal to zero
// to meet the necessary pre-conditions of this function.
assert(x >= 0);
// Call the overridden function in the subtype.
f_impl(x);
}
protected:
// Overridden by a boatload of subtypes which implement
// this non-virtual interface.
virtual void f_impl(int x) = 0;
};
이 경우 f
코드베이스의 천 곳에서 호출되고 f_impl
백 개의 하위 클래스로 대체됩니다.
이런 종류의 안전 점검은 전화를 거는 1000 곳 f
또는 재정의하는 100 곳 모두 에서 수행하기 어려울 것 f_impl
입니다.
이 진입 점을 기능을 비 가상화로 지정하면이 검사를 수행 할 수있는 중심 위치가됩니다. 그리고이 검사는 추상화를 최소화하지 않습니다. 단순히이 함수를 호출하는 데 필요한 전제 조건을 주장하기 때문입니다. 어떤 의미에서, 그것은 인터페이스가 제공하는 계약을 강화하고, x
입력을 점검하는 것이 100 개의 모든 장소에서 유효한 전제 조건을 준수하는지 확인하기위한 부담을 덜어줍니다 .
모든 언어가 C ++ 에서조차도 기본 개념에 가깝기를 원했습니다 (예 : 재정의하기 위해 별도의 함수를 정의하지 않아도 됨).
이것은 assert
사전 에이 작업을 수행하지 않은 경우 매우 유용 하며 나중에 코드베이스의 임의의 임의의 위치에 음수 값이 전달 될 때 필요하다는 것을 깨달았습니다 f
.