【问题标题】:Designing class hierarchy - multiple inheritance in Java设计类层次结构——Java中的多重继承
【发布时间】:2012-01-28 00:03:42
【问题描述】:

我知道 Java 不支持多重继承。但是如果我必须为动物王国设计一个类系统。如何表示由两种不同动物杂交而成的动物?例如,骡子(驴或马?),狮虎(狮子或老虎)。如何继承 Lion 和 Tiger 类来创建 Liger 类? 有没有办法在不将 Tiger 和 Lion 作为接口的情况下做到这一点?如果不能做接口怎么办?

【问题讨论】:

    标签: java oop


    【解决方案1】:

    在这种情况下,继承不是正确的工具。你看,狮虎不是老虎,也不是狮子。它具有两者的特征,但不是

    假设你去动物园,笼子里写着“老虎”。你往里窥视,看到这只奇怪的巨猫,你肯定认不出它是老虎。 It's cool,但不是老虎。你也不认为它是狮子。也不是substitutable

    因此,它应该组合LionTiger 并将其行为委派到正确的行为,或完全或部分“覆盖”它们的行为。

    更新:

    现在,如果你真的想要某种多重继承,比如你想从HybridFeline 派生Liger,该怎么办?看看Scala traits 的可能性。要在 Java 中实现它,您需要一个接口和一个类用于设计中要乘以“继承”的每个概念。看看here 的想法。

    【讨论】:

    • 很好的解释!现在更清楚如何处理这种情况了。我对委托和作文概念不是很熟悉,但一定会深入学习。感谢您的帮助。
    【解决方案2】:

    它们总是需要是接口iff您希望单个对象可以识别为两者。

    您通常可以将行为委托给复合类,但对于狮虎(它几乎是我最喜欢的子类),您需要决定哪种动物的行为具有优先权。狮虎可能是其中一个的直系后代,也可能不是。

    Java 只允许多个“API 继承”(接口),不允许实现。

    【讨论】:

      【解决方案3】:

      Java 不支持多类继承。考虑一下“狮子”和“老虎”可能具有的共同功能。 Java 不想解决“函数冲突”问题:

      class Lion{
          public String call(){
              return "ROAR";
          }
      }
      class Tiger{
          public String call(){
              return "growl";
          }
      }
      class Liger extends Lion, Tiger{
      }
      
      public static void main(String[] args){
          System.out.println(new Liger().call());
      }
      

      应该打印什么?

      Java 不支持多类继承,因此这不起作用——类声明的“扩展 Lion、Tiger”部分是非法的。 Java 支持接口的消歧机制,但这并没有扩展到类。

      最好的办法是将每个动物类转换为接口,然后将代码转换为这些接口的实现。 Liger 可以按如下方式实现:

      interface Liger extends Lion, Tiger { }
      class LigerImpl implements Liger{
          private Lion mom;
          private Tiger dad;
          public LigerImpl(){
              mom = new LionImpl();
              dad = new TigerImpl();
          }
          public String call(){
              if(math.random() > 0.5){
                  return mom.call();
              } else {
                  return dad.call();
          }
      }
      

      这种方法需要对每个底层实现进行显式委托;绝对没有“免费”发生。不过,Java 不会让您更接近。 Java 的设计几乎可以归结为“如果有任何含糊、不安全、未定义或可能导致类型或解析冲突的东西,请让程序员编写更多代码。”

      【讨论】:

        【解决方案4】:

        正如你所提到的,这是不可能的。此外,这也可能是设计不佳的标志(因为即使可能,它也可能带来歧义)。因此,您可能不得不尝试避免它并重新考虑您的设计。

        【讨论】:

        • 它是否带来歧义取决于子类化的内容。
        • 恕我直言,如果是 Liger,很可能会带来歧义。
        • 当然,但这总是取决于子类化的内容以及类的行为。我的观点是,说这是糟糕设计的标志是一种笼统的概括,我认为这不能被可靠地断言。
        【解决方案5】:

        建议您这样做,但反思可能会起作用。当然,使用“instanceof”永远不会奏效......

        public class Lion {
            public void roar() {
                System.out.println("Lion is roaring");
            }
        
            public void eat(String what) {
                System.out.println("Lion is eating " + what);
            }
        }
        
        public class Tiger {
            public void purr() {
                System.out.println("Tiger is purring");
            }
        
            public void eat(String what) {
                System.out.println("Tiger is eating " + what);
            }
        }
        
        import java.lang.reflect.Method;
        import java.util.ArrayList;
        
        
        public class Liger {
            public static void main(String[] args) {
                Liger liger = new Liger();
                liger.purr();
                liger.roar();
                liger.eat("food");
        
                //Result
                //Tiger is purring
                //Lion is roaring
                //Tiger is eating food
                //Lion is eating food
            }
        
            private ArrayList<Object> _extends = new ArrayList<Object>();
        
            public Liger() {
                _extends.add(new Tiger());
                _extends.add(new Lion());
            }
        
            private void invoke(String methodName, Object... args) {
                for ( Object obj : _extends ) {
                    Class cls = obj.getClass();
                    Method[] methods = cls.getMethods();
                    for ( Method m : methods ) {
                        if ( m.getName().equals(methodName) ) {
                            try {
                                m.invoke(obj, args);
                            }
                            catch ( Exception ex ) {
                                //handle me
                            }
                            continue;
                        }
                    }
                }
            }
        
            public void purr() {
                invoke("purr"); //Tiger only
            }
        
            public void roar() {
                invoke("roar"); // Lion only
            }
        
            public void eat(String what) {
                invoke("eat", what); //Both
            }
        }
        

        【讨论】:

        • 这只是一种丑陋、不可靠的委托方式。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多