在模板方法模式中有一个抽象的类,该抽象类定义了相关方法的模板,它的子类可以根据需要重写模板中的方法,但调用还是会以在抽象类中定义好的方式进行。
概述
实现一些操作时,整体步骤很固定,但是呢。就是其中一小部分需要改变,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
优点:
- 不变的部分已封装好,剩余可变的部分可随意扩展。
- 行为延迟到子类实现,但控制权在父类手中。
- 提取出了公共代码,维护变得简单。
缺点:
- 每个不同的实现都需要一个子类,会导致类的个数增加,使得系统更加庞大。
- 通过继承的方式实现,而不是组合。
使用场景:
- 多个子类共有一些方法,且逻辑相同时。
- 代码逻辑重要且复杂,可以将核心方法抽象出来设计为模板,且其它相关的方法可延迟到子类中实现时。
- 重构时模板方法模式也是一种常见的处理手段,可以把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
如果想防止不规范操作,可在模板方法前面加上
final
关键字。
示例
去餐厅吃饭,餐厅给我们提供了一个模板就是:看菜单,点菜,吃饭,付款,走人 (这里 “点菜和付款” 是不确定的由子类来完成的,其他的则是一个模板。)
先定义一个模板。把模板中的点菜和付款,让子类来实现。
//模板方法
public abstract class RestaurantTemplate {
// 1.看菜单
public void menu() {
System.out.println("看菜单");
}
// 2.点菜业务
abstract void spotMenu();
// 3.吃饭业务
public void havingDinner(){ System.out.println("吃饭"); }
// 3.付款业务
abstract void payment();
// 3.走人
public void GoR() { System.out.println("走人"); }
//模板通用结构
public void process(){
menu();
spotMenu();
havingDinner();
payment();
GoR();
}
}
具体的模板方法子类1
public class RestaurantGinsengImpl extends RestaurantTemplate {
void spotMenu() {
System.out.println("人参");
}
void payment() {
System.out.println("5快");
}
}
具体的模板方法子类2
public class RestaurantLobsterImpl extends RestaurantTemplate {
void spotMenu() {
System.out.println("龙虾");
}
void payment() {
System.out.println("50块");
}
}
客户端测试
public class Client {
public static void main(String[] args) {
//调用第一个模板实例
RestaurantTemplate restaurantTemplate = new RestaurantGinsengImpl();
restaurantTemplate.process();
}
}
总结
模板方法实际上可以理解成一个封装好了的固定流程,第一步该做什么,第二步该做什么其实都已经在抽象类中定义好了。子类可以有不同的算法实现,可以在框架不被修改的情况下实现某些步骤的算法替换。