gin*_*eer 4 java design-patterns dynamic-proxy
假设有一个接口Subject.
interface Subject { void request(); }
Run Code Online (Sandbox Code Playgroud)
我们有一个RealSubject类.假设我们想要增强RealSubject,我们可以使用包裹RealSubject的代理模式:
class Proxy implements Subject {
private RealSubject ref;
void request(){ ... }
}
Run Code Online (Sandbox Code Playgroud)
或者我们可以扩展RealSubject并覆盖该方法
class EnhancedSubject extends RealSubject {
@Override
void request() { ... }
}
Run Code Online (Sandbox Code Playgroud)
哪种方法更好?我知道Liskov原则; 让我们假设EnhancedSubject满足Liskov原则.你还在考虑继承吗?
如果没有接口Subject(即,RealSubject没有实现任何接口),似乎"inherit and override"是唯一的选项,因为在Proxy模式中没有要实现的接口.如果没有主题界面,您仍然可以应用代理模式吗?
在回答你的第一个问题时," 哪种方法更好 "?
我个人更喜欢使用接口和代理(或装饰器)模式来实现这样的东西.(参见:第16项:赞成有效Java的继承(第2版))
如果超类(RealSubject)不在您的控制之下,即在同一个包中,并且为Extension特别设计和记录,那么从版本到版本的任何实现的更改都可能会破坏子类(EnhancedSubject)的实现.基本上我所说的是:直接根据具体实现导致脆弱的代码.
在回答你的第二个问题时," 如果EnhancedSubject满足Liskov原则,你还在考虑继承吗? "
再一次使用继承是安全的,如果RealSubject并且EnhancedSubject在您的控制下并以相同的生命周期释放,但直接根据具体实现导致脆弱的代码.
希望能够让您使用Interface实现的另一点是单元测试.
例如,使用您希望应用单元测试的情况,将模拟依赖项RealSubject注入到您的Proxy实现中会更容易,Subject这样您就可以专门测试Proxy该类,而不必完全测试整个对象层次结构,RealSubject并且EnhancedSubject,只是为了确认EnhancedSubject行为符合预期.
我想可以这么说,如果它是一个非常简单的API并且将来几乎不会改变,那么具体实现就更简单了.并保持简单愚蠢(KISS)是最好的政策之一.
" 如果没有Subject接口,你还可以应用代理模式吗? "你可以注入RealSubject另一个类并在RealSubject内部使用,但如果使用的API RealSubject直接依赖于具体类,你别无选择,只能使用继承.
代理/装饰器的优点是它可以与派生类重用。这可以将代理与类的实现分开。(如果我写了无效的java,你必须原谅我......已经有一段时间了)
在这种情况下,你可能会写这样的内容:
class LoggingSubjectProxy implements Subject
{
private Subject ref;
void request()
{
log("Called request");
ref.request();
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以做
LoggingSubjectProxy l;
if(dosimple)
{
l.ref = SimpleSubject();
}
else
{
l.ref = ComplexSubject();
}
l.request()
Run Code Online (Sandbox Code Playgroud)
如果这对于您想要的扩展来说太过分了,那么您应该使用简单的继承和覆盖。