Programing

기존 클래스가있을 때 인터페이스가 다중 상속의 필요성을 대체 할 수있는 방법

즐거운 cyworld 2021. 1. 10. 16:47
반응형

기존 클래스가있을 때 인터페이스가 다중 상속의 필요성을 대체 할 수있는 방법


우선 ...이 게시물에 대해 죄송합니다. 다중 상속에 대해 논의하는 stackoverflow에 대한 많은 게시물이 있다는 것을 알고 있습니다. 하지만 Java가 다중 상속을 지원하지 않는다는 것을 이미 알고 있으며 인터페이스를 사용하는 것이 대안이되어야한다는 것을 알고 있습니다. 그러나 나는 그것을 이해하지 못하고 내 딜레마를 봅니다.

Java로 작성된 매우 크고 복잡한 도구를 변경해야합니다. 이 도구에는 연결된 멤버 계층 구조가있는 다양한 클래스 개체로 작성된 데이터 구조가 있습니다. 어쨌든...

  • Tagged여러 메서드가 있고 개체의 클래스에 따라 개체 태그를 반환하는 하나 의 클래스가 있습니다. 멤버와 정적 변수가 필요합니다.
  • 그리고 두 번째 클래스는 XMLElement객체를 연결하고 결국 XML 파일을 생성합니다. 여기에 멤버 및 정적 변수도 필요합니다.
  • 마지막으로, 거의 모든 데이터 클래스 XMLElement와 그 중 일부를 확장해야하는 많은 데이터 클래스 가 있습니다 Tagged.

좋습니다. 한 클래스 만 확장 할 수 있으므로 작동하지 않습니다. Java로 모든 것이 정상이며 다중 상속이 필요하지 않다는 것을 자주 읽었습니다. 나는 믿지만 인터페이스가 상속을 어떻게 대체해야하는지 모르겠다.

  1. 매번 동일하기 때문에 모든 데이터 클래스에 실제 구현을 넣는 것은 의미가 없지만 이것은 인터페이스에서 필요합니다 (내 생각에).
  2. 상속 클래스 중 하나를 인터페이스로 변경하는 방법을 알 수 없습니다. 여기에 변수가 있고 정확히 거기에 있어야합니다.

나는 그것을 정말로 이해하지 못하므로 누군가이 이것을 처리하는 방법을 설명해 줄 수 있습니까?


상속보다 구성 (및 위임)을 선호해야합니다.

public interface TaggedInterface {
    void foo();
}

public interface XMLElementInterface {
    void bar();
}

public class Tagged implements TaggedInterface {
    // ...
}

public class XMLElement implements XMLElementInterface {
    // ...
}

public class TaggedXmlElement implements TaggedInterface, XMLElementInterface {
    private TaggedInterface tagged;
    private XMLElementInterface xmlElement;

    public TaggedXmlElement(TaggedInterface tagged, XMLElementInterface xmlElement) {
        this.tagged = tagged;
        this.xmlElement = xmlElement;
    }

    public void foo() {
        this.tagged.foo();
    }

    public void bar() {
        this.xmlElement.bar();
    }

    public static void main(String[] args) {
        TaggedXmlElement t = new TaggedXmlElement(new Tagged(), new XMLElement());
        t.foo();
        t.bar();
    }
}

사실 Java가 Multiple Inheritance를 가져야한다는 것 외에 다른 좋은 대답은 없습니다. 인터페이스가 다중 상속의 필요성을 대체 할 수 있어야하는 요점은 충분히 반복 될 때 사실이된다는 큰 거짓말과 같습니다.

다중 상속이 이러한 모든 문제 (la-di-dah)를 유발하지만 C ++를 사용한 적이없는 Java 개발자의 주장을 계속 듣고 있다는 주장이 있습니다. 나는 또한 C ++ 프로그래머들이 "이런, 나는 C ++를 좋아하지만 그들이 다중 상속 만 제거한다면 그것은 훌륭한 언어가 될 것"이라고 말했던 것을 결코 기억하지 못한다. 사람들은 실용적 일 때는 사용했고 그렇지 않은 때는 사용하지 않았습니다.

귀하의 문제는 다중 상속이 적절한 전형적인 경우입니다. 코드를 리팩토링하라는 제안은 Java에 다중 상속이 없다는 문제를 해결하는 방법을 실제로 알려줍니다.

또한 "오, 위임이 더 낫다, la-di-dah"라는 모든 논의는 종교와 디자인을 혼동하고 있습니다. 올바른 방법은 없습니다. 상황이 더 유용하거나 덜 유용하며 그게 전부입니다.

귀하의 경우 다중 상속이 더 유용하고 더 우아한 솔루션이 될 것입니다.

다중 상속을 사용해 본 적이없고 "다중 상속이 나쁘다"라고 믿는 모든 종교인을 만족시키기 위해 코드를 덜 유용한 형식으로 리팩토링하는 한, Java가 "개선되는 것을 보지 못하기 때문에 코드를 다운 그레이드해야 할 것입니다." "그런 식으로 조만간. 너무나도 많은 사람들이 종교적 진언을 어리석은 정도로 반복해서 언어에 추가되는 것을 볼 수 없습니다.

실제로 내 솔루션은 "x extends Tagged, XMLElement"이며 그게 전부입니다.

... 위에 제공된 솔루션에서 볼 수 있듯이 대부분의 사람들은 그러한 솔루션이 너무 복잡하고 혼란 스러울 것이라고 생각합니다!

대부분의 Java 프로그래머의 능력을 압도 할 수있는 매우 무서운 솔루션이더라도 "x extends a, b"영역에 직접 도전하고 싶습니다.

위에 제안 된 솔루션에 대해 더욱 놀라운 점은 다중 상속이 나쁘기 때문에 코드를 "위임"으로 리팩토링 할 것을 제안한 모든 사람들이 동일한 문제에 직면하면 간단히 수행하여 문제를 해결할 수 있다는 것입니다. : "x는 a, b를 확장합니다"와 함께 수행하면 "위임 대 상속"에 대한 모든 종교적 주장이 사라집니다. 전체 토론은 어리 석고, 책에서 얼마나 잘 암송 할 수 있는지, 그리고 스스로 생각할 수있는 정도를 보여주는 실마리없는 프로그래머에 의해서만 진행됩니다.

다중 상속이 도움이된다는 것은 100 % 정확하며, Java가 있어야한다고 생각하면 코드에서 잘못하고있는 것입니다.


Andreas_D가 제안한 것과 비슷 하지만 내부 클래스를 사용합니다. 이렇게하면 실제로 각 클래스를 확장하고 원하는 경우 자신의 코드에서이를 재정의 할 수 있습니다.

interface IBird {
    public void layEgg();
}

interface IMammal {
    public void giveMilk();
}

class Bird implements IBird {
    public void layEgg() {
        System.out.println("Laying eggs...");
    }
}

class Mammal implements IMammal {
    public void giveMilk() {
        System.out.println("Giving milk...");
    }
}

class Platypus implements IMammal, IBird {

    private class LayingEggAnimal extends Bird {}
    private class GivingMilkAnimal extends Mammal {}

    private LayingEggAnimal layingEggAnimal = new LayingEggAnimal();

    private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal();

    @Override
    public void layEgg() {
        layingEggAnimal.layEgg();
    }

    @Override
    public void giveMilk() {
        givingMilkAnimal.giveMilk();
    }
}

먼저 모든 데이터 클래스에 실제 구현을 넣는 것은 매번 동일하기 때문에 이치에 맞지 않지만 이것은 인터페이스에서 필요합니다 (제 생각에).

태그에 집계를 사용하는 것은 어떻습니까?

  1. Tagged수업 이름 Tags.

  2. Tagged인터페이스 생성 :

    interface Tagged {태그 getTags (); }

  3. "태그"가 필요한 각 클래스를 구현 Tagged하고 tags에서 반환되는 필드를 갖도록합니다 getTags.

둘째, 상속 클래스 중 하나를 인터페이스로 변경하는 방법을 알 수 없습니다. 여기에 변수가 있고 정확히 거기에 있어야합니다.

맞습니다. 인터페이스는 인스턴스 변수를 가질 수 없습니다. 그러나 태그를 저장하는 데이터 구조는 반드시 IMO가 태그가 지정된 클래스의 일부일 필요는 없습니다. 별도의 데이터 구조에서 태그를 제거하십시오.


나는 그렇게 해결할 것입니다 : TaggedXMLElement클래스에 대한 인터페이스를 추출 하십시오 (퍼블릭 인터페이스에서 모든 메서드가 필요하지 않을 수도 있습니다). 그런 다음 두 인터페이스를 구현하고 구현 클래스에는 Tagged(실제 구체적인 Tagged클래스)와 XMLElement(실제 구체적인 XMLElement클래스)가 있습니다.

 public class MyClass implements Tagged, XMLElement {

    private Tagged tagged;
    private XMLElement xmlElement;

    public MyClass(/*...*/) {
      tagged = new TaggedImpl();
      xmlElement = new XMLElementImpl();
    }

    @Override
    public void someTaggedMethod() {
      tagged.someTaggedMethod();
    }
  }

  public class TaggedImpl implements Tagged {
    @Override
    public void someTaggedMethod() {
      // so what has to be done
    }
  }

  public interface Tagged {
     public void someTaggedMethod();
  }

(그리고 XMLElement에 대해서도 동일)


한 가지 가능한 방법;

1- 공통 기능에 대한 기본 클래스를 만들 수 있으며 인스턴스화 할 필요가없는 경우 추상화 할 수 있습니다.

2- 인터페이스를 만들고 해당 기본 클래스에서 해당 인터페이스를 구현합니다. 특정 구현이 필요한 경우 메서드를 추상화하십시오. 각 구체적인 클래스는 자체 impl을 가질 수 있습니다.

3- 구체적인 클래스에 대한 추상 기본 클래스를 확장하고이 수준에서도 특정 인터페이스를 구현합니다.


단순히 내부 (멤버) 클래스 (LRM 5.3.7)를 사용할 수 없는지 궁금하십니까? 예를 들면 다음과 같습니다 (위의 첫 번째 답변을 기반으로 함) :

// original classes:
public class Tagged {
    // ...
}

public class XMLElement {
    // ...
}

public class TaggedXmlElement {
    public/protected/private (static?) class InnerTagged extends Tagged {
      // ...
    }

    public/protected/private (static?) class InnerXmlElement extends XMLElement  {
        // ...
    }

}

This way you have a class TaggedXmlElement which actually contains all elements from the two original classes and within TaggedXmlElement you have access to non-private members of the member classes. Of course one would not use "super", but call member class methods. Alternatively one could extend one of the classes and make the other a member class. There are some restrictions, but I think they can all be worked around.


Well using Interface and single base class you are simply stating:

    A) One object can be of only one type (Which is true in real life if you think , A pigeon is a bird, a toyota is a car , etc .. A pigeon is also an animal but every bird is animal anyway, so its hierarchically above the bird type -And in your OOP design Animal class should be base of Bird class in case you need to represent it -) and

    B) 다양한 일을 할 수 있습니다 (새는 노래 할 수 있고, 날 수 있습니다. 자동차는 달릴 수 있고, 멈출 수 있습니다. 등.)
실제 사물에도 적합합니다.

물체가 여러 유형 (수평)이 될 수있는 세계에서 돌고래가 포유류이자 바다 동물이라고 가정 해 보겠습니다.이 경우 다중 상속이 더 합리적입니다. 다중 상속을 사용하여 표현하는 것이 더 쉬울 것입니다.


Using composition would be the way to go as another developer suggested. The main argument against multiple inheritance is the ambiguity created when you're extending from two classes with the same method declaration (same method name & parameters). Personally, however, I think that's a load of crap. A compilation error could easily be thrown in this situation, which wouldn't be much different from defining multiple methods of the same name in a single class. Something like the following code snippet could easily solve this dilema:

public MyExtendedClass extends ClassA, ClassB {
    public duplicateMethodName() {
        return ClassA.duplicateMethodName();
    }
}

Another argument against multiple inheritance is that Java was trying to keep things simple so that amateur developers don't create a web of interdependent classes that could create a messy, confusing software system. But as you see in your case, it also complicates and confuses things when it's not available. Plus, that argument could be used for a 100 other things in coding, which is why development teams have code reviews, style checking software, and nightly builds.

In your particular situation though, you'll have to settle with composition (see Shojaei Baghini's answer). It adds a bit of boiler plate code, but it emulates the same behavior as multiple inheritance.


I run in a similar problem on Android. I needed to extend a Button and a TextView (both inheriting from View) with additional functions. Due to not having access to their super class, I needed to find another solution. I´ve written a new class which encapsulates all the implementations:

class YourButton extends Button implements YourFunctionSet {
    private Modifier modifier;

    public YourButton(Context context) {
        super(context);
        modifier = new Modifier(this);
    }

    public YourButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        modifier = new Modifier(this);
    }

    public YourButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        modifier = new Modifier(this);
    }

    @Override
    public void generateRandomBackgroundColor() {
        modifier.generateRandomBackgroundColor();
    }
}

class Modifier implements YourFunctionSet {

    private View view;

    public Modifier(View view) {
        this.view = view;
    }

    @Override
    public void generateRandomBackgroundColor() {
        /**
         * Your shared code
         *
         * ......
         *
         * view.setBackgroundColor(randomColor);
         */
    }
}


interface YourFunctionSet {
    void generateRandomBackgroundColor();
}

The problem here is, your classes need the same super class. You can also try to use different classes, but check which type it is from, for example

public class Modifier{
private View view;
private AnotherClass anotherClass;

public Modifier(Object object) {
    if (object instanceof View) {
        this.view = (View) object;
    } else if (object instanceof AnotherClass) {
        this.anotherClass = (AnotherClass) object;
    }
}

public void generateRandomBackgroundColor(){
    if(view!=null){
        //...do
    }else if(anotherClass!=null){
        //...do
    }
}
}

So here is basically my Modifier class the class which encapsulates all implementations.

Hope this helps someone.

ReferenceURL : https://stackoverflow.com/questions/5003285/how-can-interfaces-replace-the-need-for-multiple-inheritance-when-have-existing

반응형