大话设计模式
上QQ阅读APP看书,第一时间看更新

2.7 策略模式解析

“回过头来反思一下策略模式,策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合[DPE]。”大鸟总结道。

“策略模式还有些什么优点?”小菜问道。

策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能[DP]。对于打折、返利或者其他的算法,其实都是对实际商品收费的一种计算方式,通过继承,可以得到它们的公共功能,你说这公共功能指什么?”

“公共的功能就是获得计算费用的结果GetResult,这使得算法间有了抽象的父类CashSuper。”

“对,很好。另外一个策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试[DPE]。”

“每个算法可保证它没有错误,修改其中任一个时也不会影响其他的算法。这真的是非常好。”

“哈,小菜今天表现不错,我所想的你都想到了。”大鸟表扬了小菜,“还有,在最开始编程时,你不得不在客户端的代码中为了判断用哪一个算法计算而用了switch条件分支,这也是正常的。因为,当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句[DP]。就商场收银系统的例子而言,在客户端的代码中就消除条件语句,避免了大量的判断。这是非常重要的进展。你能用一句话来概况这个优点吗?”大鸟总结后问道。

“策略模式封装了变化。”小菜快速而坚定的说。

“说得非常好,策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性[DPE]”。

“但我感觉在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象[DPE]。这本身并没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化地减轻了客户端的职责。”

“是的,这已经比起初的策略模式好用了,不过,它依然不够完美。”

“哦,还有什么不足吗?”

“因为在CashContext里还是用到了switch,也就是说,如果我们需要增加一种算法,比如‘满200送50’,你就必须要更改CashContext中的switch代码,这总还是让人很不爽呀。”

“那你说怎么办,有需求就得改呀,任何需求的变更都是需要成本的。”

“但是成本的高低还是有差异的。高手和菜鸟的区别就是高手可以花同样的代价获得最大的收益或者说做同样的事花最小的代价。面对同样的需求,当然是改动越小越好。”

“你的意思是说,还有更好的办法?”

“当然。这个办法就是用到了反射技术,不是常有人讲,‘反射反射,程序员的快乐’,不过今天就不讲了,以后会再提它的。”

“反射真有这么神奇?”小菜疑惑地望向了远方。

(注:在抽象工厂模式章节有对反射的讲解)