这个模式光看名字,真的是不知所云,我看了下简介,意思是是深入封装算法。还记得第一个策略模式讲的就是算法族的封装。下面来学习一下,看看两者有什么异同。
场景描述
这里模拟了一个甜品店制作咖啡和茶的过程。制作咖啡的过程如下:
- 把水煮沸
- 用沸水冲泡咖啡
- 把咖啡倒进杯子
- 加糖和牛奶
制作茶的过程如下:
- 把水煮沸
- 用沸水浸泡茶叶
- 把茶叶倒进杯子
- 加柠檬
可以看出制作咖啡和茶的过程非常相似。下面就来实现这个场景。
代码示例
代码示例将从正常写法写法慢慢演变,来体会该模式的好处。
正常写法
构建咖啡类
123456789101112131415161718192021222324public class Coffee {void prepareReceipe() {boilWater();brewCoffeeGrinds();pourInCup();addSugarAndMilk();}public void boilWater() {System.out.println("Boiling water");}public void brewCoffeeGrinds() {System.out.println("Dripping Coffee through filter");}public void pourInCup() {System.out.println("Pouring into cup");}public void addSugarAndMilk() {System.out.println("Adding Sugar and Milk");}}构建茶类
123456789101112131415161718192021222324public class Tea {void prepareRecipe() {boilWater();steepTeaTag();pourInCup();addLemon();}public void boilWater() {System.out.println("Boiling water");}public void steepTeaTag() {System.out.println("Steeping the tee");}public void pourInCup() {System.out.println("pouring into cup");}public void addLemon() {System.out.println("Adding Lemon");}}
可以看出,普通的写法两个类差不多,有重复代码,下面看看模板方法模式如何来消除重复代码。
模板方法
从上面的代码可以看出boilWate()
和pourInCup()
两者是一样的,很容易抽象。再仔细看下,它们的冲泡算法其实是一样的,只是有两个步骤使用的东西不一样,下面看下如何抽象。
定义咖啡因饮料超类,因为咖啡和茶叶都含有咖啡因,所以定义该超类是合理的
1234567891011121314151617181920212223242526public abstract class CaffeeineBeverate {final void prepareRecipe() {boilWater();brew();pourInCup();addCondiments();}/*** 抽象冲泡方法,由子类实现*/abstract void brew();/*** 抽象添加调味料,由子类实现*/abstract void addCondiments();void boilWater() {System.out.println("Boiling water");}void pourInCup() {System.out.println("Pouring into cup");}}定义咖啡
1234567891011public class Coffee extends CaffeeineBeverate {void brew() {System.out.println("Dripping coffee through filter");}void addCondiments() {System.out.println("Adding Sugar and Milk");}}定义茶
1234567891011public class Tea extends CaffeeineBeverate {void brew() {System.out.println("Stepping the tea");}void addCondiments() {System.out.println("Adding lemon");}}
测试
1234567891011public class Test {public static void main(String[] args) {Coffee coffee = new Coffee();coffee.prepareRecipe();System.out.println();Tea tea = new Tea();tea.prepareRecipe();}}
从代码可以看出,CaffeeineBeverate定义了整体流程,子类只要将抽象方法实现即可,简单、清晰,确实忧于普通的写法。这里说的模板方法就是preareRecipe()
,它定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。现在看来,这个跟策略模式的场景还是完全不一样的。学习的模式越来越多,越往后越容易混乱,所以要偶尔回顾回顾,理清每种模式的使用场景。书中列举了之前学的几种模式的使用场景区别:
- 模板方法:子类决定如何实现算法中的步骤
- 策略:封装可互换的行为,然后使用委托来决定要采用哪一个行为
- 工厂方法:由子类决定实例化那个具体类
另外有一点要知晓下,工厂方法是模板方法的一种特殊版本。本章节就到这里了。