如何使用受保护的方法为Java类实现装饰器模式

时间:2011-07-28 17:29:17

标签: java design-patterns

包外的子类无法访问父类实例上的受保护成员(仅在子类本身或其子类的实例上)。 JLS链接:http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.2

这是一个例子。现有的类看起来如下:

package package1;
public abstract class BaseImplementation {

    public String getResource1() {
        return processTemplate1(getBaseUrl());
    }

    public String getResource2() {
        return processTemplate2(getBaseUrl());
    }

    // Kind of 'Template Method' pattern.
    protected abstract String getBaseUrl();
}

所以打算像以下一样编写装饰器:

package package2;
public class ImplementationDecorator extends BaseImplementation {
    private BaseImplementation delegate;

    public ImplementationDecorator(BaseImplementation delegate) {
        this.delegate = delegate;
    }

    @Override
    protected String getBaseUrl() {
        return trackServer + "?redirect=" + delegate.getBaseUrl();
    }
}

代码无法编译。 getBaseUrl()在基类中具有受保护的访问权限,甚至子类也无法在父实例上访问它。

所以问题是如何使用受保护的方法来装饰这样的实例,而不使用像反射那样的“脏”技巧或将子类放到与父类同名的包中。

Java语言本身也有相同的例子(例如javax.security.auth.login.ConfigurationSpi),在我发现的Java中 - 使用来自同一个包的访问。

3 个答案:

答案 0 :(得分:3)

您在这里尝试做的是拦截行为,它在类型BaseImplementation与其派生类型之间的关系中或多或少是私有的 - 这里,您的“委托”实例您希望在ImplementationDecorator课程中进行装饰。 BaseImplementation的作者从未预料到有人想要进入中间,而BaseImplementation派生的类型的作者并没有预料到BaseImplementation以外的任何来电者都会进入那里。

相反,你正在寻找的模式看起来更像是这样,如果你不拥有所涉及的课程,我担心你无法改造:

public interface URLProvider
{
  String getBase();
}


public final class BaseImplementation
{
  public BaseImplementation(URLProvider provider)
  {
    if (null == provider)
      throw new NullPointerException();
    this.provider = provider;
  }


  public String getResource1()
  {
    return processTemplate1(provider.getBase());
  }


  public String getResource2()
  {
    return processTemplate2(provider.getBase());
  }


  private final URLProvider provider;
}

有了这个,如果某人编写了URLProvider类型的实现,那么装饰很容易,因为现在方法URLProvider#getBase()是公开的。

现在,您可能会说,与仅仅将BaseImplementation#getBaseUrl()方法更改为公开而非受保护的方法不同?不完全的。在这里,设计承认 - 甚至警告 - URLProvider实例是一种可以在任何地方使用的功能。

答案 1 :(得分:0)

这不是一个好的答案(我在评论中回答),但有一种解决办法:

public abstract class BaseImplementation {

    (...)

    protected String getBaseUrl(BaseImplementation other)
    {
        return other.getBaseUrl();
    }
}

public class ImplementationDecorator extends BaseImplementation {
    private BaseImplementation delegate;

    (...)

    @Override
    protected String getBaseUrl() {
        return trackServer + "?redirect=" + getBaseUrl(delegate);
    }
}

答案 2 :(得分:-1)

受保护的功能应该是可见的..不需要使用“脏技巧”来访问它们。

以下是受保护成员的能力:

  

可用于同一个包中的所有类,也可用于拥有受保护功能的类的所有子类。此访问甚至提供给驻留在与拥有受保护功能的类不同的包中的子类。 / p>