模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
有一个泡茶和冲咖啡的业务,他们都有差不多相似的流程。
一、不使用设计模式
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("加柠檬");
}
}
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("加牛奶和糖");
}
}
二、模板方法模式的使用
下面以一个代码样例来说明模板方法模式的使用。
//定义模板方法
public abstract class TemplateMethod {
//冲咖啡和泡茶的模板,注意这里的final,意味着该方法不可修改,即模板中方法的先后顺序被固定
final void template() {
//烧水
boilWater();
//冲泡:用沸水"浸泡"茶叶/用沸水"冲泡"咖啡
brew();
//把泡好的饮料倒进杯子
pourInCup();
//加调料
addCondiments();
}
/**这两个方法交给子类去实现**/
//茶应该"浸泡",咖啡应该"冲泡"
abstract void brew();
//茶加柠檬,咖啡加牛奶和糖
abstract void addCondiments();
/**这两个方法属于公用方法**/
void boilWater() {
System.out.println("烧水");
}
void pourInCup() {
System.out.println("倒进杯子");
}
}
public class Tea extends TemplateMethod {
public void brew() {
System.out.println("浸泡");
}
public void addCondiments() {
System.out.println("加柠檬");
}
}
public class Coffee extends TemplateMethod {
public void brew() {
System.out.println("冲泡");
}
public void addCondiments() {
System.out.println("加糖和牛奶");
}
}
public class Test {
public static void main(String[] args) {
Tea tea = new Tea();
Coffee coffee = new Coffee();
//泡茶
tea.template();
//冲咖啡
coffee.template();
}
}
三、使用钩子(hook)来做一些其它操作
//定义模板方法
public abstract class TemplateMethodWithHook {
//冲咖啡和泡茶的模板,注意这里的final,意味着该方法不可修改,即模板中方法的先后顺序被固定
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("倒进杯子");
}
//这里是个钩子,子类可决定是否需要加调料。也就是说子类可通过这个hook控制模板定义的逻辑
boolean customerWantsCondiments() {
return true;
}
}
public class TeaWithHook extends TemplateMethod {
public void brew() {
System.out.println("浸泡");
}
public void addCondiments() {
System.out.println("加柠檬");
}
public boolean customerWantsCondiments() {
//不需要加柠檬
return false;
}
}
public class CoffeeWithHook extends TemplateMethod {
public void brew() {
System.out.println("冲泡");
}
public void addCondiments() {
System.out.println("加糖和牛奶");
}
public boolean customerWantsCondiments() {
//需要加糖和牛奶
return true;
}
}
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类专注在算法本身,而由子类提供完整的实现 |
上一篇:<a href="http://muchstudy.com/2016/12/17/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%B3%BB%E5%88%97%E4%B9%8B%E5%85%AB%E5%A4%96%E8%A7%82%E6%A8%A1%E5%BC%8F/">设计模式系列之八外观模式</a>
下一篇:<a href="http://muchstudy.com/2016/12/20/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%B3%BB%E5%88%97%E4%B9%8B%E5%8D%81%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F/">设计模式系列之十迭代器模式</a>
网友评论