Java 다중 상속
Java의 여러 상속 문제를 해결하는 방법을 완전히 이해하기 위해 제가 명확히 해야 할 전형적인 질문이 있습니다.
칩시다.Animal은 하위 클래스가 .Bird ★★★★★★★★★★★★★★★★★」Horse는 수업을 .PegasusBird ★★★★★★★★★★★★★★★★★」HorsePegasus새이기도 하고 말이기도 합니다.
이게 전형적인 다이아몬드 문제인 것 같아요.으로는 '이러한 방법'을 으로 알고 '라고 하는 것을 알 수 있습니다.Animal,Bird ★★★★★★★★★★★★★★★★★」Horse 및 implement " " " 를 실행합니다.Pegasus그들로부터.
새나 말의 물건을 만들 수 있는 다른 방법이 없을까 생각하고 있었습니다.동물을 창조할 수 있는 방법이 있다면 좋겠지만 꼭 필요한 것은 아니다.
에 대한 수 .public interface Equidae이나 이 horses를 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 등)을 나타내는 인터페이스를 사용하는 것은 권장하지 않습니다(다른 인터페이스도 오리 타이핑(duck-typing)이라고 합니다만, 이것은 좋은 것입니다만, 조류인 Avialae의 생물학적 클래스입니다).로 시작하는 예: I는 은 사용하지 않는 IBird인터페이스가 필요한 이유에 대해서는 아무것도 알 수 없습니다.이치노인터페이스를 사용하여 상속 계층을 구축하고, 도움이 되는 경우 추상 클래스를 사용하고, 필요한 경우 구체적인 클래스를 구현하고, 적절한 경우 위임을 사용합니다.
오브젝트를 조합하는 기본적인 방법은 다음 두 가지가 있습니다.
- 첫 번째는 상속입니다.상속의 제한은 이미 확인되었으므로 여기서 필요한 것을 할 수 없습니다.
- 두 번째는 구성입니다.상속이 실패했으므로 컴포지션을 사용해야 합니다.
이 방법은 Animal 객체가 있는 것입니다.그런 다음 해당 개체 내에 필요한 속성 및 동작을 제공하는 개체를 추가합니다.
예를 들어 다음과 같습니다.
- Bird가 IFlier를 확장합니다.
- 말이 동물 도구 IHerbivore, IQuadruped를 확장합니다.
- Pegasus는 IHerbivore, IQuadruped, IFlier를 동물로 구현합니다.
, 이제IFlier음음음같 뭇매하다
interface IFlier {
Flier getFlier();
}
★★★★★★★★★★★★★★★★★.Bird음음음같 뭇매하다
class Bird extends Animal implements IFlier {
Flier flier = new Flier();
public Flier getFlier() { return flier; }
}
이제 상속의 장점을 모두 갖추게 되었습니다.코드를 재사용할 수 있습니다.IFlier의 컬렉션을 가질 수 있으며, 다형성의 다른 장점 등을 모두 사용할 수 있습니다.
그러나 구성으로부터 모든 유연성을 얻을 수 있습니다.다양한 인터페이스와 복합 백업클래스를 각 타입에 원하는 수만큼 적용할 수 있습니다.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();
}
}
덕타이핑의 컨셉을 제안해도 될까요?
Pegasus가 Bird and a Horse 인터페이스를 확장하도록 할 가능성이 높지만, 실제로는 duck typing이 동작을 상속하는 것이 좋습니다.이미 댓글에서 언급했듯이 페가수스는 새가 아니지만 날 수 있다.그래서 당신의 페가수스는 차라리 상속을 받아야 합니다Flyable- 및 a-interface 라고 .Gallopable- - '인터페이스'
이러한 개념은 전략 패턴에서 활용됩니다.주어진 예는 실제로 어떻게 오리가 유전되는지를 보여줍니다.FlyBehaviour ★★★★★★★★★★★★★★★★★」QuackBehaviour오리가 수 . 오리는 있을 수 있다.RubberDuck, 이 경우, 이 경우, 이 경우, '이 경우'를 만들 수도 .Duck을 하다Bird는 -어느 정도 -어느 정도 -어느 정도 -어느 정도 -어느 정도 -어느 정도 -어느 정도 -어느 정도 -는 -어느 정도 -어느 정도 -어느 정도?Duck한 도 날 수 것이다RubberDuck.
엄밀히 말하면, 한 번에 하나의 클래스만 확장하고 여러 인터페이스를 구현할 수 있지만, 소프트웨어 엔지니어링에 관여할 때는 일반적으로 답변할 수 없는 문제 특유의 해결책을 제안합니다.덧붙여서, OO의 실천은, 구체적인 수업의 연장은 아니고, 추상적인 수업의 연장은 바람직하지 않은 상속 행위를 막기 위해서입니다.동물이라는 것은 없고, 동물이라는 것은 없고, 구체적인 동물만을 사용하는 것입니다.
Java 8 이후에는 기본 방식을 사용하여 C++와 유사한 다중 상속을 실현할 수 있습니다.또한 이 튜토리얼에서는 공식 문서보다 사용하기 쉬운 몇 가지 예를 보여 줍니다.
말은 반문을 넘지 못하므로 반문이 있는 마구간에서 기르는 것이 안전하다.그래서 어떤 타입의 말이든 받아 들여 반문형 마굿간에 넣어주는 마굿간 서비스를 하고 있습니다.
그렇다면 말은 말조차 날 수 있는 동물과 같은 것일까?
예전에는 다중 상속을 많이 생각했지만, 15년 이상 프로그래밍을 해 온 지금은 다중 상속 구현에 신경 쓰지 않게 되었습니다.
다중 상속을 지향하는 설계에 대처하려고 하면, 문제의 영역을 이해하지 못했던 것을 나중에 공개하는 경우가 많습니다.
OR
만약 그것이 오리처럼 보이고 오리처럼 울부짖지만 배터리가 필요하다면, 당신은 아마도 잘못된 추상화일 것이다.
Java는 다중 상속이 없으므로 다중 상속 문제가 없습니다.이는 실제 다중 상속 문제(다이아몬드 문제)를 해결하기 위한 설계입니다.
그 문제를 완화하기 위한 다른 전략이 있다.가장 빨리 달성할 수 있는 것은 Pavel이 제안하는 Composite 객체(기본적으로 C++가 처리하는 방법)입니다.Java의 미래를 위해 C3 리니어라이제이션(또는 이와 유사한)을 통한 다중 상속이 가능할지 모르겠지만, 나는 의심스럽다.
만약 당신의 질문이 학술적이라면, 올바른 해결책은 새와 말이 더 구체적이고, 페가수스가 단순히 새와 말을 합친 것이라고 가정하는 것은 잘못된 것이다.페가수스는 새와 말과 공통되는 특정한 본질적 특성을 가지고 있다고 말하는 것이 더 맞을 것이다.이는 모리츠의 답변처럼 충분히 모델링될 수 있다.
내 생각에 그것은 당신의 요구와 당신의 동물 클래스가 당신의 코드에서 어떻게 사용되는지에 달려있다.
Pegasus 클래스 내에서 Horse and Bird 구현의 메서드와 기능을 활용할 수 있다면 Pegasus를 Bird and Horse의 구성 요소로 구현할 수 있습니다.
public class Animals {
public interface Animal{
public int getNumberOfLegs();
public boolean canFly();
public boolean canBeRidden();
}
public interface Bird extends Animal{
public void doSomeBirdThing();
}
public interface Horse extends Animal{
public void doSomeHorseThing();
}
public interface Pegasus extends Bird,Horse{
}
public abstract class AnimalImpl implements Animal{
private final int numberOfLegs;
public AnimalImpl(int numberOfLegs) {
super();
this.numberOfLegs = numberOfLegs;
}
@Override
public int getNumberOfLegs() {
return numberOfLegs;
}
}
public class BirdImpl extends AnimalImpl implements Bird{
public BirdImpl() {
super(2);
}
@Override
public boolean canFly() {
return true;
}
@Override
public boolean canBeRidden() {
return false;
}
@Override
public void doSomeBirdThing() {
System.out.println("doing some bird thing...");
}
}
public class HorseImpl extends AnimalImpl implements Horse{
public HorseImpl() {
super(4);
}
@Override
public boolean canFly() {
return false;
}
@Override
public boolean canBeRidden() {
return true;
}
@Override
public void doSomeHorseThing() {
System.out.println("doing some horse thing...");
}
}
public class PegasusImpl implements Pegasus{
private final Horse horse = new HorseImpl();
private final Bird bird = new BirdImpl();
@Override
public void doSomeBirdThing() {
bird.doSomeBirdThing();
}
@Override
public int getNumberOfLegs() {
return horse.getNumberOfLegs();
}
@Override
public void doSomeHorseThing() {
horse.doSomeHorseThing();
}
@Override
public boolean canFly() {
return true;
}
@Override
public boolean canBeRidden() {
return true;
}
}
}
또 다른 방법은 동물을 정의하는 데 상속 대신 엔티티-컴포넌트-시스템 접근 방식을 사용하는 것입니다.물론 이는 동물의 개별 Java 클래스가 아니라 해당 구성 요소에 의해 정의된다는 것을 의미합니다.
Entity-Component-System 접근법의 유사 코드는 다음과 같습니다.
public void createHorse(Entity entity){
entity.setComponent(NUMER_OF_LEGS, 4);
entity.setComponent(CAN_FLY, false);
entity.setComponent(CAN_BE_RIDDEN, true);
entity.setComponent(SOME_HORSE_FUNCTIONALITY, new HorseFunction());
}
public void createBird(Entity entity){
entity.setComponent(NUMER_OF_LEGS, 2);
entity.setComponent(CAN_FLY, true);
entity.setComponent(CAN_BE_RIDDEN, false);
entity.setComponent(SOME_BIRD_FUNCTIONALITY, new BirdFunction());
}
public void createPegasus(Entity entity){
createHorse(entity);
createBird(entity);
entity.setComponent(CAN_BE_RIDDEN, true);
}
인터페이스 계층을 설정하고 선택한 인터페이스에서 클래스를 확장할 수 있습니다.
public interface IAnimal {
}
public interface IBird implements IAnimal {
}
public interface IHorse implements IAnimal {
}
public interface IPegasus implements IBird,IHorse{
}
그런 다음 특정 인터페이스를 확장하여 필요에 따라 클래스를 정의합니다.
public class Bird implements IBird {
}
public class Horse implements IHorse{
}
public class Pegasus implements IPegasus {
}
음, 클래스는 다른 하나의 서브 클래스만 될 수 있지만, 원하는 만큼 인터페이스를 구현할 수 있습니다.
페가수스는 사실 날 수 있는 말이다.반면에, 페가수스는 걸을 수 있고 다리가 네 개인 새라고 말할 수 있습니다. 이 모든 것은 여러분이 코드를 어떻게 쓰는 것이 더 쉬울지에 달려 있습니다.
예를 들어 다음과 같이 말할 수 있습니다.
abstract class Animal {
private Integer hp = 0;
public void eat() {
hp++;
}
}
interface AirCompatible {
public void fly();
}
class Bird extends Animal implements AirCompatible {
@Override
public void fly() {
//Do something useful
}
}
class Horse extends Animal {
@Override
public void eat() {
hp+=2;
}
}
class Pegasus extends Horse implements AirCompatible {
//now every time when your Pegasus eats, will receive +2 hp
@Override
public void fly() {
//Do something useful
}
}
인터페이스는 여러 상속을 시뮬레이션하지 않습니다.자바 크리에이터는 다중 상속이 잘못되었다고 생각되므로 자바에는 그런 것이 없습니다.
두 클래스의 기능을 하나로 결합하려면 객체 구성을 사용합니다.예.
public class Main {
private Component1 component1 = new Component1();
private Component2 component2 = new Component2();
}
또, 특정의 방식을 공개하는 경우는, 그것들을 정의하고, 대응하는 컨트롤러에 콜을 위임합니다.
할 수 .- 이 경우 - 편리합니다.Component1 「」를 .Interface1 ★★★★★★★★★★★★★★★★★」Component2를 실장하다Interface2 「」를 할 수 있습니다.
class Main implements Interface1, Interface2
는 맥락이 허락합니다. 그래서 여러분이 서로 대체 가능한 물건들을 사용할 수 있다.
그래서 내 관점으로, 고객이 다이아몬드의 문제에 접근할 수가 없다.
당신이 이미 인식할 것이다, 자바의 클래스의 다중 상속,지만 인터페이스로 가능하다 가능하지 않다.당신은 또한 작문 디자인 패턴을 사용하는 것을 원할 수도 있다.
난 몇년 전에 합성에 대한 매우 포괄적인 기사를 썼다...
- 기능을 정의하기 위한 인터페이스를 정의합니다.복수의 기능에 복수의 인터페이스를 정의할 수 있습니다.이러한 기능은 특정 동물 또는 새에 의해 구현될 수 있습니다.
- 상속을 사용하여 정적이지 않은 데이터와 공개되지 않은 데이터/메서드를 공유하여 클래스 간의 관계를 설정합니다.
- 기능을 동적으로 추가하려면 Decorator_pattern을 사용합니다.이를 통해 상속 클래스 및 조합 수를 줄일 수 있습니다.
아래 예에서 더 잘 이해할 수 있습니다.
복잡성을 줄이고 언어를 단순화하기 위해 Java에서는 다중 상속이 지원되지 않습니다.
A, B, C가 3개의 클래스인 시나리오를 생각해 봅시다.C 클래스는 A 클래스와 B 클래스를 상속합니다.A클래스와 B클래스가 같은 메서드를 가지고 있으며 자녀클래스 오브젝트에서 호출하면 A클래스 또는 B클래스의 메서드를 호출하는 것이 애매해집니다.
런타임 오류보다 컴파일 시간 오류가 더 좋기 때문에 2개의 클래스를 상속하면 Java가 컴파일 시간 오류를 렌더링합니다.따라서 같은 방식을 사용하든 다른 방식을 사용하든 컴파일 시간 오류가 발생합니다.
class A {
void msg() {
System.out.println("From A");
}
}
class B {
void msg() {
System.out.println("From B");
}
}
class C extends A,B { // suppose if this was possible
public static void main(String[] args) {
C obj = new C();
obj.msg(); // which msg() method would be invoked?
}
}
Java → 인터페이스를 사용하여 다중 상속 문제를 해결합니다.
Mr. K.V.R에 의한 J2EE(코어 JAVA) 메모 51페이지
요일 - 27일
- 인터페이스는 기본적으로 사용자 정의 데이터 유형을 개발하는 데 사용됩니다.
- 인터페이스에 관해서는 복수의 상속 개념을 실현할 수 있습니다.
- 인터페이스를 통해 다형성, 동적 바인딩 개념을 실현할 수 있으므로 메모리 공간 및 실행 시간 측면에서 JAVA 프로그램의 성능을 향상시킬 수 있습니다.
인터페이스는 완전히 정의되지 않은 메서드의 컬렉션을 포함하는 구성체이거나 인터페이스는 순수하게 추상적인 메서드의 컬렉션입니다.
[...]
28일째:
인터페이스의 기능을 클래스에 재사용하기 위한 구문-1:
[abstract] class <clsname> implements <intf 1>,<intf 2>.........<intf n> { variable declaration; method definition or declaration; };위의 구문에서 clsname은 'n'개의 인터페이스에서 기능을 상속하는 클래스의 이름을 나타냅니다.'Implements'는 인터페이스의 기능을 파생 클래스에 상속하기 위해 사용되는 키워드입니다.
[...]
구문-2는 다른 인터페이스에 대한 'n'개의 인터페이스를 상속합니다.
interface <intf 0 name> extends <intf 1>,<intf 2>.........<intf n> { variable declaration cum initialization; method declaration; };[...]
구문-3:
[abstract] class <derived class name> extends <base class name> implements <intf 1>,<intf 2>.........<intf n> { variable declaration; method definition or declaration; };
문제가 해결되지 않았다.이를 충분히 모델링하여 코드 복제를 방지하려면 여러 상속 또는 혼합이 필요합니다.디폴트 기능을 가진 인터페이스는 인터페이스 내의 멤버를 유지할 수 없기 때문에 충분하지 않습니다.인터페이스 모델링은 서브클래스 또는 스태틱스에서의 코드 복제로 이어지는데, 이는 둘 다 나쁜 것입니다.
커스텀 구성을 사용하여 더 많은 컴포넌트로 분할하여 모두 구성하기만 하면 됩니다.
장난감 언어
언급URL : https://stackoverflow.com/questions/21824402/java-multiple-inheritance
'programing' 카테고리의 다른 글
| (익명의) 내부 클래스를 사용하는 것이 누출에 안전한 때는 정확히 언제입니까? (0) | 2022.09.01 |
|---|---|
| Java에서 List 개체를 초기화하려면 어떻게 해야 합니까? (0) | 2022.08.31 |
| Eclipse Java 디버깅: 소스를 찾을 수 없습니다. (0) | 2022.08.31 |
| vue 설정 후 Vee 검증 이전 값 가져오기 (0) | 2022.08.31 |
| vue js에서 localStorage의 데이터를 비활성화하는 방법 (0) | 2022.08.31 |