STRATEGY(策略)
适用性:
1.许多相关的类仅仅是行为有异。”策略“提供了一种用多个行为中的一个行为来配置一个类册方法。
2.需要使用一个算法的不同变体。
3.算法使用客户不应该知道的数据。可使用策略避免暴露复杂的、于算法有关的数据结构。
4.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的行署出现。将相关的条件分支移入他们各自的strategy类中以代替这些条件语句。
思考:
MCD向我们展示了一种基于策略编程的思想,并且将其发挥到及至。利用C++的模版和多重继承技术,提供了一个个灵活、强大,却又简单易懂的组件。从我的体会来看,基于策略编程的一个最大的好处就是迫使我不得不尽最大的努力对问题域进行正交分解。
从效果上来看,策略方法和模版方法很相似:都是把一些“差别”封装起来,提供一个统一界面。不过,策略更强调被封装的部分和使用策略的上下文之间的分离性--模版模式注重的只是如何使某些步骤允许变化。虽然效果上策略和模版模式有许多相似之处,但是策略模式并不是模版模式的扩展。模版模式关注在某个算法模版上。策略模式中策略可以和使用策略的部分共同构成接口,这在基于策略编程中再清楚不过了--虽然基于策略编程不能简单的归结为一种模式。另外,策略是需要程序员来选择的,因此,如何组合策略将是程序员需要解决的事情。
TEMPLATE METHOD(模版方法)
适用性:
1.一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
2.各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
3.控制子类扩展。
思考:
应该说,模版方法在C++代码中广泛运用的一种模式,特别是在Framework泛滥的年代--大量的虚函数重载都是该模式的运用。这样一个模式是便于学习和使用的,也因为实现的简单,其威力也是强大的,那么我们多想想它的反面。
多少次,我们在一个Framework的代码层次中穿梭,只是为了弄清一个方法如何生效的。当初,我在MFC的Doc/View框架面前,感到异常沮丧:我弄不清楚那些方法到底怎么运作起来的,即使我能够通过MSDN完成某些事情。MFC的打击给了我一个教训:远离那些没有源代码的、继承树很深的框架--我更喜欢扁平的,小巧的工具箱类。事实上,我认为Doc/View的结构完全可以用一组工具类和几个更小巧的框架类来实现。
这个观点推而广之:分离的比聚合的好。聚合在一起的框架类不如分离的工具类,成员函数不如自由函数--这在分析std::basic_string的时候得到了印证。基于策略编程恰好也满足了这个观点:宿主类基本上是完成装配工作而已。
控制子类扩展,这个观点看上去是很有价值,实践上,我觉得应该抛弃这一想法,因为它不值得作为一个指导原则。程序员控制一切,不是么?
visitor(访问者)
适用性:
1.一个对象类结构包含很多类对象,他们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
3.定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
思考:
第三点是visitor模式实现上最直接的一个描述。1和2都隐含了第三点的一个条件:定义对象结构的类很少改变,1、2中都是拥有一个相对稳定的对象集合。唯有满足“定义对象结构的类很少改变”,才能够通过运用visitor模式为这些类定义新的操作。
假设有这样一组稳定的类,都提供一个accept(v)方法,accept接收visitor对象v作为参数。实现visitor也就很简单:形式上,每个accept方法也是一个转调,用visitor对象的特定方法访问自己:v->visitT(this),而visitT是多态的。这种方法的本质就是由实际的被访问对象和实际的访问对象共同决定使用那个方法来处理,并且这个方法能够在访问类中实现。很可惜,没有见识过真实的双分派语言,支持双分派的语言是不需要visitor模式的,而且,对于对象结构类稳定性的要求也几乎没有了。