《Head First设计模式》 读书笔记09 模板方法模式
The Template Method Pattern
问题引入
咖啡和茶的冲泡步骤都差不多,可以理解为两份冲泡法都采用了基本相同的算法:
1.煮沸水。
2.用热水泡茶或咖啡。
3.把饮料倒进杯子。
4.加入适当调料(奶、糖或者柠檬片)。
如果实现不好,就会有重复的代码,算法的知识和实现会分散在许多类中,算法修改不容易,并且加入新种类的饮料也需要做很多工作。
那该怎么设计呢?
采用一个新的基类(咖啡因饮料类),其中有一个声明为final的方法(不希望被子类覆盖),为冲泡饮料的动作。
该方法(也就是模板方法)中包含了若干个小方法调用,这些小方法就是一个个基本的步骤。
对于这些步骤的处理:对各个类相同的子步骤在基类定义;而咖啡和茶有区别的步骤,声明为虚函数,依赖子类(咖啡类和茶类)自己去完成。
上面的图中,prepareRecipe()就是我们的模板方法。
它用作一个算法的模板,在这个模板中,算法内的每一个步骤都被一个方法代表了。
某些方法是由超类处理的,某些方法留给子类处理,这些需要由子类提供的方法,必须在超类中声明为抽象。
模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。
模板方法模式定义
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模板方法非常常见,对创建框架来说,由框架控制如何做事情,而由你(使用这个框架的人)指定框架算法中每个步骤的细节。(可以想想单元测试的框架JUnit的实现。)
对模板方法进行挂钩
钩子(hook)是一种被声明在抽象类中的方法,但只有空的或者默认的实现。
钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类自行决定。
某些步骤是可选的,所以可以将这些步骤实现成钩子,而不是实现成抽象方法,这样就可以让抽象类的子类的负荷减轻。
比如,也可以利用钩子做条件控制,影响抽象类中的算法流程:钩子方法在抽象类中有默认实现返回true,放在抽象类的if条件语句中,子类可以覆盖也可以不覆盖这个钩子方法。
好莱坞原则
好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
好莱坞原则可以给我们一种防止“依赖腐败”的方法。
当组件之间太多依赖的时候,设计就变得难懂了。
在好莱坞原则之下,我们允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。
换句话说,高层组件对待低层组件的方式是“别调用我们,我们会调用你”。
好莱坞原则和依赖倒置原则
依赖倒置原则教我们尽量避免使用具体类,而多使用抽象。
而好莱坞原则是用在创建框架或组件上的一种技巧,好让低层组件能够被挂钩进计算中,而且又不会让高层组件依赖底层组件。
两者的目标都是在于解耦。
模板方法模式和其他模式
策略模式和模板方法模式都封装算法,一个用组合,一个用继承。
工厂方法是模板方法的一种特殊版本。