【设计模式】模板方法
一、前言
最近复习发现AQS使用了模板方法,自定义同步器时需要重写几个AQS提供的模板方法,Spring的DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions() 方法也使用了该设计模式,于是写篇文章加深理解。
模板方法模式的定义: 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
单看这句话可能还没搞懂这个设计模式是干嘛的,下面看一个例子。
二、示例
不用设计模式,冲咖啡和泡茶的两个类分别是下面这样的。
public class Coffee { // 冲泡咖啡的算法 void prepareRecipe(){ boilWater(); // 用沸水冲泡咖啡 brewCoffeeGrinds(); pourInCup(); // 加牛奶和糖 addSugarAndMilk(); } private void addSugarAndMilk() { } private void pourInCup() { } private void brewCoffeeGrinds() { } private void boilWater() { } } public class Tea { // 泡茶的算法 void prepareRecipe(){ boilWater(); // 用沸水浸泡茶叶 steepTeaBag(); pourInCup(); // 加柠檬 addLemon(); } private void addLemon() { } private void pourInCup() { } private void steepTeaBag() { } private void boilWater() { } }
很容易就可以发现这两个类中有重复代码,boilWater()和pourInCup()都重复了可以提取出来,因为茶和饮料都是咖啡饮料可以定义一个超类CaffeineBeverage。
进一步分析,两种冲泡法其实都用了相同的算法:
- 把水煮沸
- 用热水泡咖啡或茶
- 把饮料倒进杯子
- 在饮料里加调料
所以prepareRecipe()也可以抽象成一个,如下:
final void prepareRecipe(){ boilWater(); // 交给对应的子类实现 brew(); pourInCup(); // 交给对应的子类实现 addCondiments(); }
最后,重构后的代码如下。
咖啡因饮料超类
public abstract class CaffeineBeverage { /** * 模板方法 * 定义的算法步骤 */ final void prepareRecipe(){ boilWater(); brew(); pourInCup(); addCondiments(); } /** * 添加调料 */ protected abstract void addCondiments(); /** * 冲泡 */ protected abstract void brew(); /** * 煮开水 */ private void boilWater() { System.out.println("Boiling water"); } /** * 把饮料倒进杯子 */ private void pourInCup() { System.out.println("Pouring in cup"); } }
Tea
public class Tea extends CaffeineBeverage { @Override protected void addCondiments() { System.out.println("Adding Lemon"); } @Override protected void brew() { System.out.println("Steeping the tea"); } }
Coffee
public class Coffee extends CaffeineBeverage { @Override protected void addCondiments() { System.out.println("Adding Sugar and Milk "); } @Override protected void brew() { System.out.println("Dripping Coffee through filter"); } }
代码的类图就变成了下面的样子。

类图
道理我懂,可是使用了模板方法模式之后有什么好处吗?
原本的实现 | 模板方法后的实现 |
---|---|
Coffee和Tea之间存在重复代码 | CaffeineBeverage类实现了代码复用最大化 |
Coffee和Tea控制了算法 | 由CaffeineBeverage类主导一切,拥有并保护算法 |
对算法所做的代码改变,需要修改子类很多地方 | 算法只存在一个地方,很容易修改 |
算法的知识和它的实现分散在许多类中 | CaffeineBeverage类专注算法本身,而由子类提供完整的实现 |
三、总结
设计模式这么多种,要做到灵活运用还真是长路漫漫啊。
本文作者:烟味i
本文链接:https://www.cnblogs.com/2YSP/p/11627282.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2018-10-06 SpringBoot使用sharding-jdbc分库分表