【问题标题】:Working around multiple inheritance in Java在 Java 中解决多重继承问题
【发布时间】:2014-08-07 13:05:42
【问题描述】:

我有以下基类层次结构:

  • Index(摘要)
    • RootIndex
    • AbstractSubIndex(摘要)

然后我还有两个类:

  • KPI,应该继承AbstractSubIndex,并添加自己独有的功能;
  • SubIndex,它应该继承AbstractSubIndex 的功能以及RootIndex 中的功能。我会选择默认方法(Java 8),但我的代码无法用interfaces(实例变量)编写。

更新

请注意Index 具有在其他类中继承的默认构造后功能;此构建后功能必须执行一次。合成将强制它至少执行两次,这使得合成对我来说是一个不可行的解决方案。

结束更新

我找不到任何非冗余的解决方法。

有什么想法吗?

【问题讨论】:

  • 我知道SubIndex 应该从两个类继承功能,并且它们可以很容易地被一些嵌套类继承。 SubIndex 应该从什么类型派生?
  • 它派生自AbstractSubIndexRootIndex。这两个类都具有构造 SubIndex 所需的功能。
  • 我看到您需要在 SubIndex 中提供这两个功能,但我是从编译器的 typing 角度提出的。它仍然必须有一个类型。它不能同时充当A B 类型,除非它们中最多有一个是类,但你知道这一点。
  • 对不起,我误解了你的问题:)。逻辑上它是AbstractSubIndex

标签: java inheritance multiple-inheritance


【解决方案1】:

这个解决方法,对我来说很奇怪,是基于组合的——感谢@kinga93 和@AlexR 的建议以及从头开始的面向方面的设计——但是对基类的原始代码进行了更多调整,这是我尽力避免的。

请注意,我已经将@webuster 的解决方案标记为已接受的解决方案,因为它更简单,并且可以直接完成工作。我发布这个是因为这是我最终选择的那个,因为从设计的角度来看,它对我来说更有意义,而且如果有人需要它。

  1. 我从RootIndex 中取出了不基于Index 的代码,并将其包装在一个类ParentBehaviour 中,并在其位置添加了一个引用。
  2. 我在AbstractSubIndex 中做了同样的事情,获取不基于Index 的代码,并将其包装在另一个类ChildBehavior 中,并在其位置添加一个引用。
  3. 我在SubIndex 中使用了组合,引用了ParentBehaviorChildBehavior,同时继承自AbstractSubIndex
  4. 我在KPI 中再次使用了组合,继承自AbstractSubIndex,同时引用了ChildBehavior

最后的代码是这样的:

class ParentBehavior {
    // functionality that exists in RootIndex and SubIndex, which does not
    // depend on Index.
}

class ChildBehavior {
    // functionality that exists in SubIndex and KPI, which does not depend
    // on Index.
}

abstract class Index {
    // contains post-construction code.
    void foo();
}

class RootIndex extends Index {
    ParentBehavior parentBehavior;
}

abstract class AbstractSubIndex extends Index {
    // shared code between SubIndex and KPI
    ChildBehavior childBehavior;
}

class SubIndex extends AbstractSubIndex {
    ParentBehavior parentBehavior;
}

class KPI extends AbstractSubIndex {
    // unique functionality for KPI
}

这样,SubIndexKPIAbstractSubIndex 继承 Index 的基本功能,从而无需重复从 Index 继承所需的构造后功能,同时仅具有它们所需的功能基类(通过ParentBehaviorChildBehavior)。

【讨论】:

  • 这正是我要发布的内容。简单的组合不是这里的答案,装饰器才是。
  • 你知道,我以前听说过装饰器,但从没想过就是这样。我确实需要修改设计模式 -_- 。谢谢你的提示。 :)
【解决方案2】:

好的,所以据我了解,我认为以下内容可能会削减它。假设您的 Index 类的简化方案为

abstract class Index {

    public Index() {
        // your code here
        // ...

        postConstruct();
    }

    void postConstruct() {
        // your post construction stuff
    }

    // assumed just one abstract method, may be a thousand like it
    abstract void foo(); 
}

你的派生类型为

class RootIndex extends Index {
    // ...

    @Override
    void foo() {
        // your stuff
    }

    public void bar() {
        // your additional stuff
    }
}

abstract class AbstractIndex extends Index {
    // ...
}

我会这样做的方式是这样的。创建一个公开RootIndex附加功能签名的接口:

interface AdditionalFunctionalityInterface {
    void bar();
}

并让RootIndex 实现它。然后,我将解决您的一次 postConstruct 问题,如下所示:

class SubIndex extends AbstractIndex implements AdditionalFunctionalityInterface {

    private class AuxRootIndex extends RootIndex {
        @Override
        void postConstruct() {
            // DON'T do what super.postConstruct() does
            // might as well be empty if you wish
        }
    }

    // composition
    private AuxRootIndex myRootIndex;

    @Override
    void foo() {
        // your stuff

        // a little bit unclear here, you can keep the one from
        // AbstractIndex or the one from RootIndex if you want
        myRootIndex.foo();
    }


    @Override
    public void bar() {
        myRootIndex.bar();
    }
}

除非有其他条件和限制,我希望以上内容可以解决问题。您的代码可能与上面的格式不同,但您可以通过将附加代码提取到单独的方法中来将其转换为这种格式。

【讨论】:

    【解决方案3】:

    解决此类问题的标准方法是委托。

    根据需要定义接口及其层次结构。定义具体的类。当属于不同继承分支的A类和B类应该共享功能时,在C类中实现它,并从A和B调用C的方法。

    【讨论】:

    • 感谢您的回答,但我有点不清楚。我认为您的意思是我使用组合,这对我不起作用。请检查问题中的更新部分。
    • Index 的默认构建后逻辑必须在每个实例、每个子类或应用程序生命周期内运行一次?
    • 每个类/子类实例一次。
    【解决方案4】:

    使用组合而不是继承。在类中为 AbstractIndex 或 RootIndex(甚至两个字段)声明一个字段。

    【讨论】:

    • 我忘记在问题中写一些东西,这使得这个解决方案对我来说不可行。 Index 中有默认的构造后功能,它在 RootIndex 和 AbstractSubIndex 中都被继承。在您提到的所有情况下,组合将至少执行此功能两次。对不起,我之前没有提到这部分;现在更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-08
    • 2017-07-02
    • 2011-01-09
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多