2005年2月17日星期四

《ASD》设计模式:Template和Strategy

Q:virtual函数可以是private函数吗?
A:可以。不仅可以,这还是Template模式中的常见方法。
Q:那么子类实现这些不能被调用的虚函数有什么意义呢?
A:意义在于这些虚函数是由一个public的非虚函数来调用的。
Template模式的核心是有一个相对固定的调用框架和可以被替换的具体步骤,父类实现这个调用框架,子类实现具体步骤。如果不想让客户随便的使用这些具体步骤,就可以把它们设为private函数,只能由父类的框架来调用。所以,对于一个类似于framework的产品,Template模式几乎是必不可少的。

Template模式是一种非常强大而且有趣的模式,但是它常常会被滥用。根本原因是:仔细考量Template模式的结构,会发现Template模式的实现完全是依靠继承。而GOF说过,要优先考虑聚合然后才是继承。
Template是直接继承,这使得具体实现的子类依赖于调用者父类,这不符合DIP原则(还能想起什么是DIP吗?)这就使得子类中的方法不能为其他对象所用。而常常,对于一个具体实现有不止一种策略,而每种策略都需要这个具体实现中的某个方法。这种时候,Template模式会变得很麻烦。
那么如何才能让它符合DIP原则呢?这就需要在调用者和实现者之间添加一个接口。这个接口声明所有的可能被调用的步骤;调用者包含这个接口,调用接口中的方法;实现者从这个接口中派生,实现接口中的所有步骤。
这个改动将大大地改善之前设计的灵活性。多种策略可以共享同一个实现了,当然一个策略也可以应用于多种实现上。策略和实现之前完全的松绑了。
实际上,这种设计是把之前的Templage模式便成了Strategy模式。
所以当,涉及到要把上层逻辑和下层实现分离的时候,应当优先考虑Strategy模式,而不是Template模式。

那么Template模式是否就没有用了呢?看到这种问句的人都该明白,答案一定是否定的。
刚才已经提到了,Template模式的问题之一是实现者的方法不能被其他对象使用。
而本文一开始就说了,Template模式可以把虚函数设成私有函数,以防止其他对象滥用具体实现类。也就是说,这是一个故意加上去的限制。
现在明白了吧,Template的不灵活原本就是他的意图,本意就是要给使用者添加一些限制。例如一个framework的产品,并不希望出现自己所不愿意见到的调用方法(那样也许会对产品本身造成破坏),所以就会使用Template模式。

结论是:Template模式在于限制,Strategy模式在于分离。

没有评论: