Java:委托模式和受保护的方法

时间:2013-04-26 11:33:48

标签: java design-patterns decorator delegation

我一直在使用委托模式将工厂创建的对象包装在第三方库中。最近,库在基类中添加了一个受保护的方法,我的包装器类不再起作用了。有没有人在不诉诸反思的情况下有一个好的解决方案?

这是在第三方库及其包中,

public class Base {
    public void foo();

    protected void bar(); // Newly added
}

这是我自己的包,

public class MyWrapper extends Base {
    private Base delegate;

    public MyWrapper(Base delegate) {
        this.delegate = delegate;
    }

    public void foo() {
        delegate.foo()
    }

    protected void bar() {
        // Don't know what to do
    }
}
编辑:我原来的帖子不清楚。这两个类在不同的包中。

回答我为何需要代表团的问题。这是委托/包装模式的典型用例,我不能在几行代码中显示它。该库公开Base类,但其工厂中的实际对象是Base的派生类。实际的类根据配置而变化。所以我不知道代表是什么。因此,直接继承模式在这里不起作用。

5 个答案:

答案 0 :(得分:4)

Access Levels
Modifier    Class   Package Subclass    World
public      Y          Y        Y         Y
protected   Y          Y        Y         N
no modifier Y          Y        N         N
private     Y          N        N         N

protected也有package访问权限,您是否看到任何具体问题:

class Base {
        public void foo(){};

        protected void bar(){}; // Newly added
    }

    class MyWrapper  {
        private Base delegate;

        public MyWrapper(Base delegate) {
            this.delegate = delegate;
        }

        public void foo() {
            delegate.foo();
        }

        protected void bar() {
            // Don't know what to do
            delegate.bar(); //since its in same package, it can be referenced, do you expect compile time error?
        }
    }

此外,虽然使用委托者模式为什么包装器类扩展Base类,但我没有看到具体需要,因为您已经有Base的实例。对我而言,它似乎更像是一个装饰者。

答案 1 :(得分:1)

您不需要(或不应该?)委托该方法。

如果库定义了受保护的方法。它不希望用户(当然在不同的包中)调用该方法,除非创建该类型的子类。你试图破坏规则。

如果你想这样做,有一种方法,你创建一个Base的子类型,比如SubBase,你创建SubBase的对象而不是Base,然后将subBase传递给您的包装器。然后你可以在你的包装器bar()方法中写delegate.bar()这样,SubBase实际上是委托,或者说你的包装器委托SubBase而不是Base }

我想你知道我的意思,所以我只是不输入示例代码,只有这一行我想这已经足够了:

//Wrapper

 private SubBase delegate;

如果你有SubBase,你会发现不再需要包装器了。您甚至可以在public void pubBar()中定义SubBase,然后拨打this.bar()。通过这种方式,SubBase的所有对象都可以访问受保护的方法(via pubBar()),无论从哪个包

答案 2 :(得分:1)

我得到的印象是Base类是接口或抽象类。如果是这样,您必须实现bar()方法,例如使用下面列出的三种方法中的任何一种。

旁注,如果Base是普通班级,则您没有做任何事情(调用MyWrapper.bar()实例实际上会调用Base.bar()


委托父对象

如果bar()方法在第三方API中用作回调,通常是个好主意:

@Override
protected void bar() {
    delegate.bar();
}

什么都不做

刚刚添加了一个空方法以避免编译错误:

@Override
protected void bar() {
    // silently ignored
}

抛出异常

严重阻止使用新方法:

@Override
protected void bar() {
    throw new UnsupportedOperationException("not implemented");
}

作为旁注,更强大的构造是更倾向于composition over inheritance将您的实现与第三方实现分离,例如

public class MyWrapper {    // does not extend Base
    private Base delegate;

    public MyWrapper(Base delegate) {
        this.delegate = delegate;
    }

    public void foo() {
        delegate.foo()
    }

    // does not have to implement bar()
}

答案 3 :(得分:0)

我正在使用Spring在Wrapper中注入来自另一个模块的“Base delegate”,并且用于获取委托我正在使用pojo工厂。

<bean id="interfaceDelegate" factory-bean="DelegatePojoFactory"
    factory-method="getMyDelegateInstance">
    <constructor-arg index="0">
        <value>OnLine</value>
    </constructor-arg>
</bean>

<bean id="wrapper" class="path.Wrapper">
      <property name="delegate" ref="interfaceDelegate"></property>
</bean>

答案 4 :(得分:0)

如果您不需要您的委托人是基类的实际实例,您可以简单地删除该关系:

public class MyWrapper {
    private Base delegate;

    public MyWrapper(Base delegate) {
        this.delegate = delegate;
    }

    public void foo() {
        delegate.foo()
    }

}

这是否适合您,在很大程度上取决于您的其他代码,我现在对您的需求并不完全清楚。

如果库定义了一个提供由抽象基类实现的公共方法的接口,那么您可以合理地实现该接口而不继承抽象基类,这也可能满足您的需求。