继续这个问题:Why can't you reduce the visibility of a method in a Java subclass?
我需要创建与B
类几乎完全相同的类A
,但B
无法执行A
可以执行的某些操作。
作为一个懒惰的程序员,我试图继承A
,只是为了问候B
无法降低A
方法的可见性。杜!..
现在A
是来自供应商的API,我的目的是封装此API,以便更容易使用。
我想知道解决这个问题的最佳做法是什么?
答案 0 :(得分:18)
两个选项:
如果您需要B
保持与A
相同的界面(以便客户端代码可以使用两者中的任何一个而不进行更改),您可以覆盖B
中的“禁止”方法并让他们抛出一个UnsupportedOperationException
。例如:
public class A
{
public int allowedMethod() { ... }
public int forbiddenMethod() { ... }
}
public class B extends A
{
public int forbiddenMethod()
{
throw new UnsupportedOperationException("Sorry, not allowed.");
}
}
或者,如果您确实希望B
的API成为A
的API的子集,那么只需B
包含A
的实例,并且委托方法适当调用。
public class A
{
public int allowedMethod() { ... }
public int forbiddenMethod() { ... }
}
public class B
{
private A a;
public int allowedMethod()
{
return a.allowedMethod();
}
}
答案 1 :(得分:9)
使用Composition rather than Inheritance。
即。 B类包含对A类的引用,并在其上内部调用方法。
答案 2 :(得分:4)
当需要更简单或更简单的界面时,可以使用外观。
您必须在外部接口周围创建自己的包装器类(Facade Pattern)。
interface Foreign
{
void dontWantThis();
void keepThis();
}
interface/class MyForeign
{
void keepThis();
}
然后,实现将有一个Foreign实例,它可以引用调用。
答案 3 :(得分:3)
如果B不能做所有的事情,你就不能把B视为A。
也许你需要一个包装器,而不是一个子类。
修改强>
所以你明白你永远不会减少子类方法的“可见性”:)。抛出异常或不做任何事情都不会降低可见性,因此需要一个包装器。有时,这种情况是设计糟糕的信号(有时只是)。
这与circle-ellipse problem非常相关。
答案 4 :(得分:2)
您可以构建一个提供简化API的包装类,或者您可以从要禁用的方法中抛出UnsupportedOperationException
之类的异常。
答案 5 :(得分:1)
解决方案可能会使用“组合”而不是“内在”。 您可以在类B中具有类型A的属性。然后仅公开B中要实际实现的那些方法
答案 6 :(得分:1)
您可以考虑另一种选择。
假设你想减少某些类的API:
public class LargeApi {
public void doFoo() { ... }
public void doBar() { ... }
public void doBaz() { ... }
...
...
}
这样客户只会说doFoo方法(或者你更喜欢使用的任何方法):
public interface ReducedApi {
void doFoo();
}
但是为了在预期的LargeApi的任何地方使用ReducedApi的实例,你需要一种方法来回到LargeApi(最好没有强制转换):
public interface ReducedApi {
void doFoo();
LargeApiClass asLargeApiClass();
}
强制客户端使用新的简化API的示例实现可能如下所示:
public class ReducedApiImpl
extends LargeApi
implements ReducedApi {
// Don't let them instantiate directly, force them to use the factory method
private ReducedApiImpl() {
}
// Notice, we're returning the ReducedApi interface
public static ReducedApi newInstance() {
return new ReducedApiImpl();
}
@Override
public void doFoo() {
super.doFoo();
}
@Override
public LargeApi asLargeApi() {
return this;
}
}
现在您的客户可以使用缩减的api来处理常见情况,但在需要时可以使用缩减的api:
ReducedApi instance = ReducedApiImpl.newInstance();
instance.doFoo();
callSomeMethodExpectingLargeApi(instance.asLargeApi());
答案 7 :(得分:0)
我会使用适配器模式。 http://en.wikipedia.org/wiki/Adapter_pattern