读书笔记:headfirst 设计模式 ,大话设计模式
模板方法模式
- 模板方法模式就是提供了一个很好的代码复用平台
- 模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现.
- 模板方法模式是通过把不变的行为搬移到超类,去除子类中的重复代码来提现它的优势
概念:定义一个操作中的算法骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构既可重定义该算法的某些特定步骤.
代码案例
冲泡咖啡和茶叶
普通实现:
public class Coffee {
void prepareRecipe() {
boilWater();
brewCoffee();
pourInCup();
addSugerAndMilk();
}
public void boilWater() {
System.out.println("烧开水");
}
public void brewCoffee() {
System.out.println("冲泡咖啡");
}
public void pourInCup() {
System.out.println("倒进杯子");
}
public void addSugerAndMilk() {
System.out.println("加糖和牛奶");
}
}
public class Tea {
void prepareRecipe() {
boilWater();
steepTea();
pourInCup();
addLemon();
}
public void boilWater() {
System.out.println("烧开水");
}
public void steepTea() {
System.out.println("浸泡茶叶");
}
public void pourInCup() {
System.out.println("倒进杯子");
}
public void addLemon() {
System.out.println("加柠檬");
}
}
模板方法实现:
类图
// 提取抽象咖啡因类饮料
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 抽取重复实现
void boilWater() {
System.out.println("烧开水");
}
// 留给子类实现
public abstract void brew();
// 抽取重复实现
void pourInCup() {
System.out.println("倒进杯子");
}
// 留给子类实现
public abstract void addCondiments();
}
public class Coffee extends CaffeineBeverage {
@Override
public void brew() {
System.out.println("冲泡咖啡");
}
@Override
public void addCondiments() {
System.out.println("加糖和牛奶");
}
}
public class Tea extends CaffeineBeverage {
@Override
public void brew() {
System.out.println("浸泡茶叶");
}
@Override
public void addCondiments() {
System.out.println("加柠檬");
}
}
模板方法与钩子
钩子:钩子是一种被声明在抽象类中的方法,但是有空或者默认实现.
- 钩子的存在可以让子类有能力对算法的不同点进行挂钩
- 要不要挂钩由子类决定(覆盖)
代码
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (hook()) {
addCondiments();
}
}
// 钩子方法 默认加调料
boolean hook() {
return true;
}
// 抽取重复实现
void boilWater() {
System.out.println("烧开水");
}
// 留给子类实现
public abstract void brew();
// 抽取重复实现
void pourInCup() {
System.out.println("倒进杯子");
}
// 留给子类实现
public abstract void addCondiments();
}
public class CoffeeWithHook extends CaffeineBeverage {
private boolean addFlag = true;
public CoffeeWithHook(boolean addFlag) {
super();
this.addFlag = addFlag;
}
public CoffeeWithHook() {
super();
}
@Override
public void brew() {
System.out.println("冲泡咖啡");
}
@Override
public void addCondiments() {
System.out.println("加糖和牛奶");
}
// 覆写钩子方法 影响抽象类算法流程 根据addFlag控制是否增加调料
@Override
boolean hook() {
return addFlag;
}
Q&A
- Q:使用模板方法时,什么时候使用抽象方法,钩子?
- A:子类提供算法中某个方法或步骤时使用抽象方法,如果这个部分是可选的,使用钩子
- Q:钩子的作用?
- A:子类可以实现算法中的可选部分,让子类能够对模板方法中的某些即将发生(before)或刚刚发生的(after)步骤做出反应
好莱坞原则
好莱坞原则 :别调用(打电话给)我们,我们会调用(打电话)给你
好莱坞原则和模板方法
Q:低层组件不可以调用高层组件的方法吗?
A:并不尽然,应该避免让高层和低层组件之间有明显的环状依赖
模板方法是一个常见的设计模式,许多实现并不是完全遵循模板方法的设计规则
比如:Arrays.sort()静态方法 和Comparable 的compareTo方法
模板方法模式与策略模式
- 策略模式是使用非继承既组合,让客户可以选择(委托)不同的算法家族成员
- 模板方法中算法结构不变,个别步骤有不同的实现(使用继承)细节
模板方法模式与工厂方法模式
- 模板方法定义了算法的步骤,把这些步骤的实现延迟到子类
- 由子类绝对实例化哪个具体类,工厂方法是模板方法的一种特殊版本