包外的子类无法访问父类实例上的受保护成员(仅在子类本身或其子类的实例上)。 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中 - 使用来自同一个包的访问。
答案 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>