设计模式之模板方法模式笔记
- 说明
- Template Method(模板方法)
- 目录
- 模板方法模式示例类图
- 抽象类
- 包菜类
- 菜心类
- 测试类
说明
记录下学习设计模式-模板方法模式的写法。JDK使用版本为1.8版本。
Template Method(模板方法)
意图:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
结构:
其中:
- AbstractClass(抽象类)定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤:实现模板方法,定一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。
- ConcreteClass(具体类)实现原语操作以完成算法中与特定子类相关的步骤。
适用性:
- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中,以避免代码重复。
- 控制子类扩展。模板方法旨在特定点调用“hook”操作(默认的行为,子类可以在必要时进行重定义扩展),这就只允许在这些点进行扩展。
使用场景:
- 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
- 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
目录
模板方法模式示例类图
以该UML类图实现模板方法模式示例。
抽象类
package com.example.deesign_patterns.template_method;
//抽象类(定义模板方法和基本方法)
public abstract class AbstractClass {
//模板方法定义,烹饪方法
public final void cookProcess(){
pourOil();
heatOil();
pourVegetable();
pourSauce();
fry();
}
//第一步:倒油是一样的,所以直接实现
public void pourOil(){
System.out.println("倒油");
}
//第二步:热油是一样的,所以直接实现
public void heatOil(){
System.out.println("热油");
}
//第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
public abstract void pourVegetable();
//第四步:倒调位料是不一样的
public abstract void pourSauce();
//第五步:翻炒是一样的,所以直接实现
public void fry(){
System.out.println("炒啊炒啊炒到熟啊");
}
}
包菜类
package com.example.deesign_patterns.template_method;
//包菜类
public class ConcreteClassCabbage extends AbstractClass{
@Override
public void pourVegetable() {
System.out.println("下锅的蔬菜是包菜");
}
@Override
public void pourSauce() {
System.out.println("下锅的酱料是辣椒");
}
}
菜心类
package com.example.deesign_patterns.template_method;
//菜心类
public class ConcreteClassHeart extends AbstractClass{
@Override
public void pourVegetable() {
System.out.println("下锅的蔬菜是菜心");
}
@Override
public void pourSauce() {
System.out.println("下锅的酱料是蒜蓉");
}
}
测试类
package com.example.deesign_patterns.template_method;
//测试类
public class Client {
public static void main(String[] args) {
//炒包菜,创建包菜对象
ConcreteClassCabbage cabbage=new ConcreteClassCabbage();
//炒菜心,创建菜心对象
//ConcreteClassHeart cabbage=new ConcreteClassHeart();
//调用烹饪方法
cabbage.cookProcess();
}
}
好处:
- 提高代码复用性。将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。
- 实现了反向控制。通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制,并符合开闭原则。
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结果,它提高了代码阅读的难度。