Java:可以访问超类的字段和方法的策略模式吗?

时间:2018-08-05 17:01:07

标签: java inheritance design-patterns interface multiple-inheritance

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

Parent

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

1)第一个解决方案:

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{
}

此问题是它复制了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()所需的所有其他方法。当需要更多变化时,该问题将成倍恶化。

2)环顾四周后,我发现了设计策略Strategy,该策略可用于实现行为,但是由于更改需要访问fooB()的字段和方法而很尴尬:

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); } 的字段和方法是公共的,整个过程都令人费解。我还担心性能开销,因为ParentFooAFooBBarA间接访问了BarB方法,尽管我尚未对其进行测试。

是否有更好的方式来实现这一行为?

2 个答案:

答案 0 :(得分:1)

  

但是,现在“父级”的字段和方法是公共的,整个   事情感觉很令人费解。

您的Barable和Fooable实现本身并不拥有上下文,因此它们必须使用上下文对象(此处为子类public)中的Parent方法来查询和操作它。
但是只有Parent方法必须是公共的,而不是其字段。

例如,这将是ParentFooA实现的公平实现:

abstract class Parent{

    private Fooable fooable;  // internals 
    private Barable barable;  // internals

    private String sharedString;  // internals
    private Integer sharedInteger;  // internals

    // public access        
    public foo(){ fooable.foo(); }
    public bar(){ barable.bar(); }

    public String getSharedString(){
        return sharedString;
    }

    public Integer getSharedInteger(){
        return sharedInteger;
    }

    public String updateSharedData(String string, Integer integer){
        // apply some logic and controls if required
        this.string = string;
        this.integer = integer;
    }

}


class FooA extends ImplementableParent implements Fooable{
    FooA(Parent p){ 
       super(p); 
    }
    @Override 
    foo(){  
        if (p.getSharedString().equals("...)){
           // some logic
           p.updateSharedData("new value", newIntegerValue);
        }
    }
}

作为旁注,将Parent定义为已包装FooableBarable实例的依赖项,意味着Fooable可以反向操作Barable。< br /> 您的实际需求中没有说明。如果要防止这种情况,则应为上下文定义一个特定的类,该类包含要在两种合同(FooableBarable)之间共享的数据和方法,而另一类用于ChildXXX子类的总合同。
而不是在构造函数中传递Parent实例,而是传递Context实例。

答案 1 :(得分:1)

您过于依赖IMO。清洁代码的一般规则是组合优先于继承。

您想要的是这样的

one  alex@gmail.com
two  andy@gmail.com
four  ankit@gmail.com
five  amar@gmail.com

有几种创建方法。

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

interface Foo { void foo(); } interface Bar { void bar(); } interface FooBar extends Foo, Bar {} 类不需要实现这些;它可以提供这样做的内部类,以便那些内部类能够访问受保护的成员。

Parent

借助实用程序委托类(与解决方案B不同)和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 } 中的工厂方法,您可以将它们组合到实现两个接口的实例中。

Parent

Here's a running version of this code

现在,内部类实质上是组装到 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()); } } 实例中的策略。完全不需要继承FooBar

在界面中使用合并方法

您可能根本不想在Parent类中进行合并,而要在界面中进行:

Parent

然后您将像这样使用

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()); Foo是功能性接口,因此可以组合Bar对象的方法,而不必使用内部类。

Parent

然后

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

Like this