本文总结归纳自《Head First 设计模式》第八章-模板方法模式。用于复习。
The Template Method defines the steps of the algorithm and allows subclasses to provide the implementation for one or more steps.
模板方法定义了算法的一些列步骤,并且允许子类实现其中的一步或多步。
问题汇总
- 定义和作用
- 使用场景
- 包含的设计原则
- hook的作用
- Java API有哪些实际运用?如何体现?
- 模板方法和策略模式的区别
定义:
模板方法在method中定义了算法的骨架并将一些步骤推迟到子类中实现。该模式在不改变算法结构的情况下,让子类重新定义了算法中某些步骤的内容。
结构:
- Abstract class(父类), 包含template method()和其使用的一系列步骤op1(),op2()…
- Concreate class(具体类,子类),实现步骤中某些步骤op2(),op4()….
实例:煮咖啡,煮茶
咖啡和茶的准备中,都包含下列步骤:1、烧热水,2、将茶叶包放入水中/倒入速溶咖啡,3、倒入茶杯中,4、添加调料(奶泡等等)。这就是整个算法的步骤流程。而step2和step4就是不同具体子类需要实现的内容。
父类:Beverage
prepareReceipe是模板方法,brew和addCondiments需要子类实现的步骤。
public abstract class Beverage {
//templelate method
final void prepareReceipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
//concrete method
public void boilWater() {
System.out.println("Boling the water");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
//subclass to implement
public abstract void brew();
public abstract void addCondiments();
}
Concrete class(具体子类)
Tea和Coffee看代码理解。
public class Coffee extends Beverage{
@Override
public void brew() {
System.out.println("brew the coffee");
}
@Override
public void addCondiments() {
System.out.println("add mocha into coffee");
}
}
public class Tea extends Beverage{
@Override
public void brew() {
System.out.println("brew the tea");
}
@Override
public void addCondiments() {
System.out.println("add sth into tea");
}
}
标准的Template Method
绝大部分和实例相似,但是这里添加了一个hook方法。hook的作用是让用户选择性挂载一些方法,hook可以被重写也可以不重写。我们这里就在上例的代码中添加hook
public abstract class AbstractClass {
final public void templateMethod() {
primitiveOperation1();
primitiveOperation2();
concreteOperation();
hook();
}
abstract public void primitiveOperation1();
abstract public void primitiveOperation2();
final public void concreteOperation() {
}
void hook() {};
}
Hook
这里通过hookcustomerWantsCondiments
来让用户确定是否添加调料,子类可以重写该方法添加相应的判断,也可以不重写,这就是hook的用途。
将可选的功能设计为hook而不是抽象方法。
public abstract class Beverage {
//templelate method
final void prepareReceipe() {
boilWater();
brew();
pourInCup();
//hook
if(customerWantsCondiments())
{
addCondiments();
}
}
//hook
public boolean customerWantsCondiments() {
return true;
}
....
....
....
}
设计模式:The Hollywood Principle
Don’t call us,we’ll call you.
通过该原则,允许底层的组件可以将自己挂载到系统中,而不是高层组件决定何时用它们。
在设计Template Method时就是告诉subclass,“Don’t call us, we’ll call you”.
Abstract Class来决定何时调用subclass实现的具体步骤,并且将精力集中于抽象部分,而不是具体的子类(Tea、Coffee等等)。
好莱坞原则和依赖倒置原则区别
都是致力于解耦(decouple)
1. 依赖倒置原则:是致力于避免使用具体类,而更多的使用抽象
2. 好莱坞原则:是致力于建立一种框架或组件,以允许底层组件能挂载到系统中,而不用创建底层和高层之间的依赖。
Java API中模板方法的使用
比如数组排序方法sort
里面只调用了mergeSort(...)
,mergeSort就可以看做模板方法。里面定义了排序的步骤,使用了compareTo、swap等步骤。
比较鸭子怎么办?Java中无法继承数组,但是设计者提供了接口
Comparable
,实现该接口并且实现compareTo()
。然后调用数组的sort方法就可以排序一个Duke
数组。java.io中,InputStream有read方法,是由子类实现的,而这个方法又会被模板方法read(byte b[], int off, int len)去使用。
Swing中的JFrame也使用了
Tmeplate method
,当你需要绘图的时候,需要继承JFrame
,然后重写其中的Paint()
方法,这个方法就是hook
方法,通过覆盖该方法可以将自己的代码加入到JFrame
的算法中。
模板方法和策略模式的区别
-
- Template Method控制算法的框架,而把具体的有区别的步骤交给子类实现。
- 策略模式放弃控制算法。致力于给用户提供多组可选择的算法。用组合的方式实现。
-
- Template Method有更少的对象,更有效率(一点点)。
- 策略模式使用组合而更加灵活,而且可以在运行时更改算法。
-
- Template Method依赖父类中实现的方法。
- 策略模式不依赖任何人,甚至能自己实现一整套算法。