Java의 다중 상속 문제를 해결하는 방법을 완전히 이해하기 위해 명확히해야 할 고전적인 질문이 있습니다.
I 클래스가 있다고 가정하자 Animal
이 하위 클래스가 Bird
그리고 Horse
내가 클래스 만들 필요가 Pegasus
에서 확장 Bird
하고 Horse
있기 때문에이 Pegasus
새와 말 모두이다.
이것이 고전적인 다이아몬드 문제라고 생각합니다. 내가 이것을 해결하는 고전적인 방법을 이해할 수있는 것에서 Animal
, Bird
및 Horse
클래스를 인터페이스로 만들고 구현 Pegasus
하는 것입니다.
새와 말의 개체를 만들 수있는 문제를 해결하는 다른 방법이 있는지 궁금합니다. 동물을 만들 수있는 방법이 있다면 훌륭하지만 꼭 필요한 것은 아닙니다.
답변
public interface Equidae
말이나 public interface Avialae
새 와 같은 동물 클래스 (생물학적 의미의 클래스)에 대한 인터페이스를 만들 수 있습니다 (생물학자가 아니므로 용어가 틀릴 수 있습니다).
그런 다음 여전히
public class Bird implements Avialae {
}
과
public class Horse implements Equidae {}
그리고 또한
public class Pegasus implements Avialae, Equidae {}
의견에서 추가 :
중복 코드를 줄이기 위해 구현하려는 동물의 공통 코드가 대부분 포함 된 추상 클래스를 만들 수 있습니다.
public abstract class AbstractHorse implements Equidae {}
public class Horse extends AbstractHorse {}
public class Pegasus extends AbstractHorse implements Avialae {}
최신 정보
하나 더 자세하게 추가하고 싶습니다. Brian 이 말했듯 이 이것은 OP가 이미 알고있는 것입니다.
그러나 인터페이스에 대한 “다중 상속”문제를 무시하고 이미 구체적인 유형 (예 : Bird)을 나타내는 인터페이스를 사용하지 않는 것이 좋습니다 (기타 참조). 오리 타이핑도 좋습니다.하지만 생물학적 의미의 조류 인 Avialae). 또한 대문자 ‘I’로 시작하는 인터페이스 이름 (예 : IBird
인터페이스가 필요한 이유에 대해서는 아무 것도 알려주지 않음) 을 사용하지 않는 것이 좋습니다 . 그것은 질문과 다른 점입니다. 인터페이스를 사용하여 상속 계층을 구성하고, 유용한 경우 추상 클래스를 사용하고, 필요한 경우 구체적인 클래스를 구현하고 필요한 경우 위임을 사용하십시오.
답변
객체를 결합하는 데는 두 가지 기본 접근 방식이 있습니다.
- 첫 번째는 상속 입니다. 상속의 한계를 이미 식별 했으므로 여기서 필요한 것을 수행 할 수 없음을 의미합니다.
- 두 번째는 Composition 입니다. 상속이 실패 했으므로 구성을 사용해야합니다.
이것이 작동하는 방식은 Animal 객체가 있다는 것입니다. 그런 다음 해당 개체 내에 필요한 속성과 동작을 제공하는 추가 개체를 추가합니다.
예를 들면 다음과 같습니다.
- 조류는 동물 구현 IFlier 연장
- 말 확장 동물 구현 IHerbivore, IQuadruped
- 페가수스 확장 동물 구현을 IHerbivore, IQuadruped, IFlier
이제 IFlier
다음과 같이 보입니다.
interface IFlier {
Flier getFlier();
}
따라서 Bird
다음과 같습니다
class Bird extends Animal implements IFlier {
Flier flier = new Flier();
public Flier getFlier() { return flier; }
}
이제 당신은 상속의 모든 장점을 가지고 있습니다. 코드를 재사용 할 수 있습니다. IFliers 컬렉션을 가질 수 있고 다형성 등의 다른 모든 장점을 사용할 수 있습니다.
그러나 컴포지션의 모든 유연성도 있습니다. Animal
각 비트의 설정 방법에 대해 필요한만큼의 제어를 통해 각 유형에 원하는만큼 다양한 인터페이스와 복합 백킹 클래스를 적용 할 수 있습니다 .
구성에 대한 전략 패턴 대안 적 접근
수행하는 작업과 방법에 따른 대안은 Animal
기본 클래스에 여러 가지 동작 목록을 유지하기 위해 내부 컬렉션을 포함시키는 것입니다. 이 경우 전략 패턴에 더 가까운 것을 사용하게됩니다. 그것은 코드 단순화 측면에서 이점을 제공하지만 (예 : 또는 Horse
에 대해 아무것도 알 필요가 없습니다 ) 인터페이스 접근 방식을 수행하지 않으면 다형성 등의 많은 이점을 잃게됩니다.Quadruped
Herbivore
답변
나는 바보 같은 생각을 가지고있다 :
public class Pegasus {
private Horse horseFeatures;
private Bird birdFeatures;
public Pegasus(Horse horse, Bird bird) {
this.horseFeatures = horse;
this.birdFeatures = bird;
}
public void jump() {
horseFeatures.jump();
}
public void fly() {
birdFeatures.fly();
}
}
답변
오리 타이핑 의 개념을 제안해도 될까요?
페가수스가 새와 말 인터페이스를 확장시키는 경향이 있지만 오리 타이핑은 실제로 행동을 상속해야한다고 제안합니다 . 의견에서 이미 언급했듯이 페가수스는 새가 아니라 날 수 있습니다. 따라서 페가수스는 오히려- Flyable
인터페이스를 상속 받아- 인터페이스라고 말해야합니다 Gallopable
.
이런 종류의 개념은 전략 패턴 에서 활용됩니다 . 주어진 예는 실제로 오리 상속이 방법을 보여줍니다 FlyBehaviour
그리고 QuackBehaviour
아직도, 오리가있을 수 있습니다 예를 들어 RubberDuck
, 비행 할 수있다. 그들은 또한 Duck
확장을 한 Bird
클래스 로 만들 수 있었지만 모든 Duck
사람들은 심지어 가난한 사람들조차도 날 수 있기 때문에 약간의 유연성을 포기했을 것 RubberDuck
입니다.
답변
기술적으로 말하면 한 번에 하나의 클래스 만 확장하고 여러 인터페이스를 구현할 수 있지만 소프트웨어 엔지니어링을 할 때는 일반적으로 대답 할 수없는 문제 별 솔루션을 제안합니다. 그건 그렇고, OO 관행 은 콘크리트 클래스를 확장 하지 않고 원치 않는 상속 동작을 방지하기 위해 추상 클래스 만 확장하는 것입니다. “동물”과 같은 동물 개체는 없으며 콘크리트 동물 만 사용하는 것은 없습니다.
답변
2014 년 2 월 현재 개발 단계에있는 Java 8에서는 기본 메소드 를 사용 하여 일종의 C ++와 유사한 다중 상속을 달성 할 수 있습니다 . 공식 문서보다 작업을 시작하기에 더 쉬운 몇 가지 예를 보여주는 이 자습서 를 살펴볼 수도 있습니다 .
답변
말이 반 문을 넘을 수 없으므로 말을 반 문으로 안정되게 유지하는 것이 안전합니다. 따라서 나는 말 유형의 모든 품목을 받아들이고 반문으로 안정된 말 주택 서비스를 설정했습니다.
말처럼 날 수있는 동물 같은 말입니까?
다중 상속에 대해 많이 생각했지만 15 년 이상 프로그래밍을 했으므로 더 이상 다중 상속 구현에 신경 쓰지 않습니다.
여러 상속을 향한 디자인에 대처하려고 할 때 종종 문제 영역을 이해하지 못했음을 발표했습니다.
또는