模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
有一个泡茶和冲咖啡的业务,他们都有差不多相似的流程。
一、不使用设计模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Tea { void process() { boilWater(); steepTeaBag(); pourInCup(); addLemon(); }
public void boilWater() { System.out.println("烧水"); }
public void steepTeaBag() { System.out.println("泡茶"); }
public void pourInCup() { System.out.println("倒进杯子"); }
public void addLemon() { System.out.println("加柠檬"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Coffee { void process() { boilWater(); brewCoffeeGrinds(); pourInCup(); addSugarAndMilk(); }
public void boilWater() { System.out.println("烧水"); }
public void brewCoffeeGrinds() { System.out.println("冲咖啡"); }
public void pourInCup() { System.out.println("倒进杯子"); }
public void addSugarAndMilk() { System.out.println("加牛奶和糖"); } }
|
二、模板方法模式的使用
下面以一个代码样例来说明模板方法模式的使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public abstract class TemplateMethod { final void template() { boilWater(); brew(); pourInCup(); addCondiments(); } abstract void brew(); abstract void addCondiments();
void boilWater() { System.out.println("烧水"); } void pourInCup() { System.out.println("倒进杯子"); } }
|
1 2 3 4 5 6 7 8
| public class Tea extends TemplateMethod { public void brew() { System.out.println("浸泡"); } public void addCondiments() { System.out.println("加柠檬"); } }
|
1 2 3 4 5 6 7 8
| public class Coffee extends TemplateMethod { public void brew() { System.out.println("冲泡"); } public void addCondiments() { System.out.println("加糖和牛奶"); } }
|
1 2 3 4 5 6 7 8 9 10
| public class Test { public static void main(String[] args) { Tea tea = new Tea(); Coffee coffee = new Coffee(); tea.template(); coffee.template(); } }
|
三、使用钩子(hook)来做一些其它操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public abstract class TemplateMethodWithHook { final void template() { boilWater(); brew(); pourInCup(); if (customerWantsCondiments()) { addCondiments(); } } abstract void brew(); abstract void addCondiments();
void boilWater() { System.out.println("烧水"); } void pourInCup() { System.out.println("倒进杯子"); }
boolean customerWantsCondiments() { return true; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class TeaWithHook extends TemplateMethod {
public void brew() { System.out.println("浸泡"); } public void addCondiments() { System.out.println("加柠檬"); }
public boolean customerWantsCondiments() { return false; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class CoffeeWithHook extends TemplateMethod {
public void brew() { System.out.println("冲泡"); } public void addCondiments() { System.out.println("加糖和牛奶"); }
public boolean customerWantsCondiments() { return true; } }
|
1 2 3 4 5 6 7 8 9 10
| public class TestHook { public static void main(String[] args) { TeaWithHook teaHook = new TeaWithHook(); CoffeeWithHook coffeeHook = new CoffeeWithHook(); teaHook.template(); coffeeHook.template(); } }
|
四、比较
| 不使用设计模式 |
使用模板方法模式 |
| Coffee和Tea主导一切;它们控制了算法 |
TemplateMethod控制了一切,它拥有算法,并且保护这个算法 |
| Coffee和Tea之间存在着重复的代码 |
通过TemplateMethod类实现了代码的复用 |
| 如果算法变了,需要修改Coffee和Tea类 |
新增算法或调整顺序只需要修改TemplateMethod类 |
| 由于类的组织不具有弹性,新加入第三种类型时需要完全重写一份 |
由于有模板存在,只需要实现差异化的逻辑即可 |
| 算法的知识和它的实现会分散在许多类中 |
TemplateMethod类专注在算法本身,而由子类提供完整的实现 |
上一篇:设计模式系列之八外观模式
下一篇:设计模式系列之十迭代器模式
留言
欢迎交流想法。留言会通过 GitHub Issues 保存,首次使用需要登录 GitHub。