一个最简单的设计模式-模板方法
程序员文章站
2022-06-03 19:05:12
《Head First设计模式》已经读了不止一遍,但是始终没有进行系统的进行总结。所以近期开始总结设计模式相关的知识,从模板方法模式开始,因为是一个我认为是最简单的设计模式。(推荐视频资源 "23个设计模式" ) 提出&解决问题 提出问题 实现制作咖啡功能 。且制作咖啡需要四个步骤 : 1. 烧水 ......
《head first设计模式》已经读了不止一遍,但是始终没有进行系统的进行总结。所以近期开始总结设计模式相关的知识,从模板方法模式开始,因为是一个我认为是最简单的设计模式。(推荐视频资源)
提出&解决问题
提出问题
实现制作咖啡功能。且制作咖啡需要四个步骤 :
- 烧水
- 冲泡咖啡
- 倒入杯中
- 加糖
代码实现
/** * 一杯加糖咖啡 * * @author jann lee * @date 2019-07-14 18:37 */ public class coffee { /** * 制作一杯加糖咖啡 */ public void preparerecipe() { boilwater(); steepteabag(); portincup(); addlemon(); } /** * step1: 烧水 */ private void boilwater() { system.out.println("烧水..."); } /** * step2:冲泡咖啡 */ private void steepteabag() { system.out.println("冲泡咖啡..."); } /** * step3: 倒入杯中 */ private void portincup() { system.out.println("倒入杯中..."); } /** * step4: 加糖 */ private void addlemon() { system.out.println("加糖..."); }
再次提出问题此时此刻我需要一杯柠檬茶呢?【烧水,冲泡茶包,倒入杯中,加柠檬】
这个问题当然很简单,我们只需要如法炮制即可。
public class tea { /** * 制作一杯柠檬茶 */ public void preparerecipe(){ boilwater(); brewcoffeegrinds(); portincup(); addsugarandmilk(); } /** * step1: 烧水 */ private void boilwater() { system.out.println("烧水..."); } /** * step2:冲泡咖啡 */ private void brewcoffeegrinds() { system.out.println("冲泡茶包..."); } /** * step3: 倒入杯中 */ private void portincup() { system.out.println("倒入杯中..."); } /** * step4: 加柠檬 */ private void addsugarandmilk() { system.out.println("加入柠檬片..."); } }
思考
如果此时我们又需要一杯不加柠檬的茶,加奶的咖啡...,当然我们可以按照上面方式重新依次实现即可。但是如果你是一个有经验的程序员,或者你学习过设计模式。你可能会发现以上功能实现的步骤/流程固定,当需求发生变化时,只有小部分步骤有所改变。
优化代码
根据面向对象程序的特点,既抽象,封装,继承,多态。我们可以对代码进行抽象,将公共代码提取到基类。我们将咖啡和茶抽象成咖啡因饮料,将其中相同的两步,烧水和倒入杯中再父类中实现,将冲泡和添加调料延迟到子类。
- 定义一个基类
public abstract class cafeinebeverage { /** * 制作一杯咖啡因饮料 */ public void preparerecipe() { boilwater(); brew(); portincup(); addcondiments(); } /** * step1: 烧水 */ private void boilwater() { system.out.println("烧水..."); } /** * step2:冲泡 */ protected abstract void brew(); /** * step3: 入杯中 */ private void portincup() { system.out.println("倒入杯中..."); } /** * step4: 加调料 */ protected abstract void addcondiments(); }
// 一杯加糖咖啡 public class coffeebeverage extends cafeinebeverage{ @override protected void brew() { system.out.println("冲泡咖啡..."); } @override protected void addcondiments() { system.out.println("加糖..."); } }
// 一杯柠檬茶 public class teabeverage extends cafeinebeverage { @override protected void brew() { system.out.println("冲泡茶包..."); } @override protected void addcondiments() { system.out.println("加柠檬..."); } }
模板方法模式
如果按以上方式对代码进行了优化,其实就实现了模板方法模式。一下是模板方法模式相关概念。
动机
- 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但是各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现
- 如何在确定稳定的操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?
定义
定义一个操作中算法的骨架(稳定),而将一些步骤延迟(变化)到子类。template method使得子类可以不改变(复用)一个算法的结构,即可重新定义(override)该算法的特定步骤。
要点总结
- template method是一种非常基础性的设计模式,在面向对象系统中,有着大量的应用。他用最简洁的机制(抽象类的多态,为很多应用框架提供了灵活的扩展点,是代码复用方面最基本实现结构)
- 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是template method的典型应用
- 在具体实现方面,被template method调用得虚方法可以有实现,也可以没有实现(抽象方法),但一般推荐设置为protected方法
类图: