模板方法模式------行为型设计模式
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式(Template Method Pattern) 实际上是封装了一个固定流程,该流程由几个步骤组成,具体步骤可以由子类进行不同实现,从而让固定的流程产生不同的结果。
模板方法模式 非常简单,其实就是类的继承机制,但它却是一个应用非常广泛的模式。
模板方法模式 本质:抽象封装流程,具体进行实现
主要解决
当完成一个操作具有固定的流程时,由抽象固定流程步骤,具体步骤交给子类进行具体实现(固定的流程,不同的实现)。
优缺点
优点
- 封装不变,扩展可变:父类封装了具体流程以及实现部分不变行为,其它可变行为交由子类进行具体实现;
- 流程由父类控制,子类进行实现:框架流程由父类限定,子类无法更改;子类可以针对流程某些步骤进行具体实现;
缺点
- 抽象规定了行为,具体负责实现,与通常事物的行为相反,会带来理解上的困难(通俗地说,“父类调用了子类方法”);
使用场景
- 多个子类有公有的方法,并且逻辑基本相同时;
- 重要,复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现;
- 重构时,模板方法模式 是一个经常使用的模式,把相同的代码抽取到父类,然后通过钩子函数约束其行为;
UML图
从 UML 类图中,我们可以看到,模板方法模式 主要包含两种角色:
- 抽象模板(AbstractClass):抽象模板类,定义了一套算法框架/流程;
- 具体实现(ConcreteClass):具体实现类,对算法框架/流程的某些步骤进行了实现;
/** * * 抽象模板类:定义炒菜流程 */ public abstract class CookVegetable { protected void wash() { System.out.println("洗菜"); } protected void pourOil() { System.out.println("热油下锅"); } protected void fry() { System.out.println("下菜翻炒"); } // 具体调料由菜决定 protected abstract void pourSauce(); // 具体炒菜流程 public final void cook() { this.wash(); this.pourOil(); this.fry(); this.pourSauce(); System.out.println("起锅吃菜"); } }
/** * 炒豆芽 * */ public class CookBeanSprout extends CookVegetable { @Override protected void pourOil() { System.out.println("热锅少油"); } @Override protected void fry() { System.out.println("快速翻炒"); } @Override protected void pourSauce() { System.out.println("加盐和少量生抽"); } }
/** * 炒茄子 * */ public class CookEggplant extends CookVegetable { @Override protected void wash() { System.out.println("去除头尾,然后用水洗下"); } @Override protected void pourOil() { System.out.println("热锅多油"); } @Override protected void pourSauce() { System.out.println("加盐和鸡精"); } }
运行
public class Client { public static void main(String[] args) { System.out.println("准备炒豆芽"); CookVegetable cookVegetable = new CookBeanSprout(); cookVegetable.cook(); System.out.println(); System.out.println("准备炒茄子"); cookVegetable = new CookEggplant(); cookVegetable.cook(); } }