Java:可以访问父类(super class)字段和方法的策略模式?

标签 java inheritance design-patterns interface multiple-inheritance

我有一个抽象类 Parent ,其中包含抽象方法 foo()bar() 以及其他非抽象方法和字段。我需要创建 4 个子类(以及稍后更多)来涵盖 foo()bar() 上不同变体的每种组合:fooA()fooB()barA()barB()。这些变体需要访问 Parent 的其他字段和方法。 换句话说,如果Java支持多重继承,那么我会得到类似的东西:

abstract class Parent{
    abstract foo(){}
    abstract bar(){}
    //other fields and methods that will be accessed foo and bar are PROTECTED
}

abstract class FooA extends Parent{
    @Override
    foo(){ ... }
}
abstract class FooB extends Parent{
    @Override
    foo(){ ... }
}
abstract class BarA extends Parent{
    @Override
    bar(){ ... }
}
abstract class BarB extends Parent{
    @Override
    bar(){ ... }
}

class ChildAA extends FooA, BarA{   
}

class ChildAB extends FooA, BarB{
}

class ChildBA extends FooB, BarA{
}

class ChildBB extends FooB, BarB{
}

我找到了两种解决方案,每种都有效,但也差不多。有更好的方法来实现这种行为吗?我的解决办法如下:

1)第一个解决方案:

abstract class Parent {
    foo(){ 
        /* behaves like fooA */
    }
    //other fields and methods that will be accessed foo and bar are PROTECTED
}

class ChildAA extends Parent{
    barA(){ ... }
}

class ChildAB extends Parent{
    barB(){ ... }
}

class ChildBA extends ChildAA{
    @Override
    foo(){ /* behaves like fooB */ }
|

class ChildBB extends ChildAB{
    @Override 
    foo(){ /* behaves like fooB */ }
}

这样做的问题是,它重复了 fooB() 的代码以及仅 fooB() 需要的所有其他方法。当需要更多变化时,问题会呈指数级恶化。

2)环顾四周后,我发现了设计模式Strategy,它可以用来实现行为,但很尴尬,因为变体需要访问Parent的字段和方法:

abstract class Parent{
    Fooable fooable;
    Barable barable;
    foo(){ fooable.foo(); }
    bar(){ barable.bar(); }
    //other fields and methods that will be accessed foo and bar are PUBLIC
}

abstract class ImplementableParent{
    Parent p;
    ImplementableParent(Parent p) { this.p = p; }
}

interface Fooable{
    foo();
}
class FooA extends ImplementableParent implements Fooable{
    FooA(Parent p){ super(p); }
    @Override 
    foo(){ /* behaves like FooA */ }
}
class FooB extends ImplementableParent implements Fooable{
    FooB(Parent p){ super(p); }
    @Override 
    foo(){ /* behaves like FooB */ }
}

interface Barable{
    bar();
}
class BarA extends ImplementableParent implements Barable{
    BarA(Parent p) { super(p); }
    @Override 
    bar() { /* behaves like BarA */ }
}
class BarB extends ImplementableParent implements Barable{
    BarB(Parent p) { super(p); }
    @Override 
    bar() { /* behaves like BarB */ }
}

class ChildAA extends Parent{
    fooable = new FooA(this);
    barable = new BarA(this);
}

class ChildAB extends Parent{
    fooable = new FooA(this);
    barable = new BarB(this);
}

class ChildBA extends Parent{
    fooable = new FooB(this);
    barable = new BarA(this);
}

class ChildBB extends Parent{
    fooable = new FooB(this);
    barable = new BarB(this);
}

这消除了变化的重复,并且可以扩展以适应更多的变化。然而,现在 Parent 的字段和方法都是公共(public)的,整个事情感觉非常复杂。我还担心性能开销,因为 FooAFooBBarABarB 访问 Parent 间接方法,尽管我还没有测试过。

是否有更好的方法来实现该行为?

最佳答案

在我看来,你过于依赖继承了。干净代码的一般规则是优先选择组合而不是继承。

你想要的是这样的:

interface Foo {
    void foo();
}
interface Bar {
    void bar();
}
interface FooBar extends Foo, Bar {}

有多种方法可以创建它。

父类中的内部类和工厂方法

Parent 类不需要实现这些;它可以提供内部类来执行此操作,以便这些内部类能够访问 protected 成员。

class Parent {
    protected int neededByFoo;
    protected int neededByBar;

    class FooA implements Foo {
        public void foo() {
            doStuffWithNeededByFoo();
        }
    }
    class FooB implements Foo {
        public void foo() {
            doStuffWithNeededByFoo();
        }
    }
    // same for the BarA and BarB implementations
}

借助实用程序委托(delegate)类(与您的解决方案 B 不同)和 Parent 中的工厂方法,您可以将它们组合到实现两个接口(interface)的实例中。

    private static class FooBarDelegate implements FooBar {
        Foo fooDelegate;
        Bar barDelegate;
        private FooBarDelegate(Foo f, Bar b) { fooDelegate = f; barDelegate = b; }
        public void foo() { fooDelegate.foo(); }
        public void bar() { barDelegate.bar(); }
    }

    public FooBar fooAbarA() {
        return new FooBarDelegate(new FooA(), new BarA());
    }
    public FooBar fooBbarA() {
        return new FooBarDelegate(new FooB(), new BarA());
    }
    public FooBar fooAbarB() {
        return new FooBarDelegate(new FooA(), new BarB());
    }
    public FooBar fooBbarA() {
        return new FooBarDelegate(new FooB(), new BarB());
    }
}

Here's a running version of this code .

现在,内部类本质上是被组装到 FooBar 实例中的策略。根本不需要子类化 Parent

在界面中使用组合方法

您可能根本不想在 Parent 类中进行组合,而是在接口(interface)中进行组合:

interface FooBar extends Foo, Bar {
    public static FooBar combine(Foo f, Bar b) {
        return new FooBar() {
            foo() { f.foo(); }
            bar() { b.bar(); }
        }
    }
}

然后你就可以像这样使用

Parent p = new Parent();
FooBar fb = FooBar.combine(new p.FooA(), new p.BarA());
fb = FooBar.combine(new p.FooA(), new p.BarB());

等等。

方法引用

由于 FooBar 是函数式接口(interface),因此您可以组合 Parent 对象的方法,而不是使用内部类。

class Parent {
    public void fooA() { // do stuff }
    public void fooB() { // do stuff }
    public void barA() { // do stuff }
    public void barB() { // do stuff }
}

然后

FooBar fb = FooBar.combine(p::fooA, p::barA);
fb = FooBar.combine(p::fooA, p::barB);
// and so on

Like this .

关于Java:可以访问父类(super class)字段和方法的策略模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51696449/

相关文章:

java - 如何知道一个方法被主类调用了多少次?

java - 运行 "empty"Undertow 时每秒 HTTP 请求数的限制因素是什么?

java - 如何在不启动新的 jvm 进程的情况下从 ant 调用 maven?

C#:关于接口(interface)、实现和继承的困惑

javascript - Javascript 是一种基于原型(prototype)的语言是什么意思?

c++ - 清除指针的回调(MCVE : auto eject traitor Soldier from Vehicle)

java - 在对象中表示优先级/偏好的最佳方式是什么?

java - 使用时间选择器使警报管理器每天重复

inheritance - 当我尝试使用继承时,为什么我会从 dart 中收到以下错误?

.net - WCF服务器如何将更改通知WCF客户端? (更好的解决方案,然后是简单的轮询,例如 cometd 或长轮询)