假设有一个接口(interface)Subject。
interface Subject { void request(); }
我们有一个 RealSubject 类。假设我们想要增强 RealSubject,我们可以使用环绕 RealSubject 的代理模式:
class Proxy implements Subject {
private RealSubject ref;
void request(){ ... }
}
或者我们可以扩展 RealSubject 并覆盖该方法
class EnhancedSubject extends RealSubject {
@Override
void request() { ... }
}
哪种方法更好?我知道 Liskov 原则;让我们假设 EnhancedSubject 满足 Liskov 原则。你还考虑继承吗?
如果没有接口(interface) Subject(即 RealSubject 不实现任何接口(interface)),似乎“继承和覆盖”是唯一的选择,因为在代理模式中没有接口(interface)可以实现。如果没有 Subject 接口(interface),你还能应用 Proxy 模式吗?
最佳答案
在回答您的第一个问题“哪种方法更好”时?
我个人更喜欢使用接口(interface)和代理(或装饰器)模式来实现类似的东西。 (参见:第 16 条:优先考虑 Effective Java (2nd Edition) 的继承)
如果父类(super class) (RealSubject
) 不受您的控制,即在同一个包中,并且是专门为扩展设计和记录的,那么从一个版本到另一个版本对其实现的任何更改都可能会破坏您的实现子类 (EnhancedSubject
)。基本上我要说的是:直接依赖于具体的实现会导致代码脆弱。
针对你的第二个问题,“如果EnhancedSubject
满足Liskov原则,你还考虑继承吗?”
如果 RealSubject
和 EnhancedSubject
在您的控制之下并以相同的生命周期发布,但是直接依赖于具体实现会导致代码脆弱。
另一个有希望影响您使用接口(interface)实现的点是 Unit 测试。
例如,使用您想要应用单元测试的情况,将 RealSubject
的模拟依赖项注入(inject)到您的 Proxy
实现中会容易得多Subject
这样您就可以专门测试 Proxy
类,而不必完全测试整个对象层次结构,RealSubject
和 EnhancedSubject
,只是为了确认 EnhancedSubject
的行为符合预期。
我想可以这么说,如果它都是一个非常简单的 API,并且它在未来几乎不会改变,那么具体的实现只会更简单。保持简单愚蠢 (K.I.S.S.) 是最好的政策之一。
“如果没有 Subject 接口(interface),你还能应用 Proxy 模式吗?”
您可以将 RealSubject
注入(inject)另一个类并在内部使用 RealSubject
,但是如果使用 RealSubject
的 API 直接依赖于具体类,则您没有其他选择选择,而是使用继承。
关于java - 代理模式与覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3965334/