模板方法(Template Method)模式的定义如下: 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。
模板模式的主要优点如下:
主要缺点如下:
模板模式涉及三个角色:
我们的报销系统分为日常费用报销和差旅费用报销,报销的流程是先根据报销单上带的费用计算出报销金额,然后计算出报销单中的补贴金额(若是差旅类型报销才需要计算补贴,日常报销不需要计算补贴),最后调用第三方接口创建流程。这个场景就适合用模板设计模式实现。
定义报销流程的算法框架,算法框架使用final
修饰,对于必须要子类实现的方法用abstract
关键字修饰。
public abstract class AbstractReimburse {
/**
* 用作算法的模板
* 定义成final,以免子模板改变算法的顺序
*/
final void calAndCreateFlow(){
BigDecimal totalMoney;
BigDecimal changeMoney = calChangeMoney();
BigDecimal subsidyMoney = BigDecimal.ZERO;
if(hasTravel()){
subsidyMoney = calSubsidyMoney();
}
totalMoney = changeMoney.add(subsidyMoney);
createWorkeFlow(totalMoney);
}
/**
* 具体方法,子类判断是否需要实现
* @param totalMoney 报销总金额
*/
protected void createWorkeFlow(BigDecimal totalMoney) {
System.out.println("开始创建流程...,总报销金额:"+totalMoney);
//todo
}
/**
* 钩子方法,由子类决定是否实现,钩子可以作为条件控制,影响抽象类中的算法流程
* 判断是否需要计算补贴
*/
boolean hasTravel() {
return false;
}
/**
* 抽象方法,需要子类去实现
* 返回需要报销的费用金额
* @return 报销的费用总金额
*/
abstract BigDecimal calChangeMoney();
/**
* 返回需要报销的补贴金额
*/
abstract BigDecimal calSubsidyMoney();
}
/**
* 差旅类报销实现逻辑
*/
public class TravelReimburse extends AbstractReimburse{
@Override
BigDecimal calChangeMoney() {
System.out.println("差旅类报销计算费用金额");
return new BigDecimal(1000);
}
@Override
BigDecimal calSubsidyMoney() {
System.out.println("差旅类报销需要计算补贴");
return new BigDecimal(500);
}
@Override
boolean hasTravel(){
return true;
}
}
/**
* 日常类报销实现逻辑
*/
public class DailyReimburse extends AbstractReimburse{
@Override
BigDecimal calChangeMoney() {
System.out.println("日常类报销计算费用金额");
return new BigDecimal(100);
}
@Override
BigDecimal calSubsidyMoney() {
return BigDecimal.ZERO;
}
}
public class ReimburseClient {
public static void main(String[] args) {
//差旅类报销处理逻辑
TravelReimburse travelReimburse = new TravelReimburse();
travelReimburse.calAndCreateFlow();
System.out.println("===========================");
//日常类报销处理逻辑
DailyReimburse dailyReimburse = new DailyReimburse();
dailyReimburse.calAndCreateFlow();
}
}
模板模式应该是众多设计模式中相对简单的一种,但是它使用的频率可一点也不低,在各种开源框架代码中都可以看到它的身影,模板设计模式的应用场景主要有以下几类:
tips 记得几年前电话面试的时候,面试官问我有没有用过模板设计模式,我回答说“啊,模板?你说的是freemarker吗?巴拉巴拉一大堆”,然后只听电话嘟嘟嘟响,留我一人在风中凌乱。