✨这里是第七人格的博客✨小七,欢迎您的到来~✨
🍅系列专栏:设计模式🍅
✈️本篇内容: 模板模式✈️
🍱 本篇收录完整代码地址:gitee.com/diqirenge/d… 🍱
楔子
如果你不止读过一篇小七关于设计模式的文章,你会发现小七的写作方式,其实是有一个模版的。大致如下:楔子——>需求背景——>分析设计——>URL图——>模块名称——>模块地址——>模块描述——>代码实现——>实现要点——>总结。小七在写文章的时候,只需要往模板中填充内容就好了,不但文章层级结构显得很清晰,也大大加快了小七的写作速度。都说艺术源于生活,写代码又何尝不是如此呢?
需求背景
假设我们现在有一个标准的退款流程,分为3步:
1、申请
2、审核
3、退款
然后我们有2种退款的入口,一种是后台运营申请退款,一种是用户申请退款,他们第1步的申请细节有差异,第2的审核和第3步的退款是一样的,但是是否需要进行审核是可配置的。
分析设计
根据需求我们可以知道,现在的退款操作已经有标准流程了,所以我们可以弄一个抽象类,把这3步的顺序固定下来,抽象在一个方法内。因为他们的申请方法有差异,那么可以考虑交给子类自己去实现。又因为第2步和第3步是一样的,所以我们可以在抽象类中提供2个共有方法,至于是否可以调用审核,做一个钩子方法判断即可。
UML图
根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码
模块名称
template
模块地址
模块描述
模板模式代码示例
代码实现
1、编写抽象类
该类的主要作用是要抽象公共的流程和方法
/**
* 抽象的退款流程
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/28
*/
public abstract class AbstractRefund {
/**
* 退款流程
*/
protected final void doRefund() {
// 步骤一:申请
this.apply();
// 是否需要审核
if (needVerify()) {
// 步骤二:审核
this.verify();
}
// 步骤三:退款
this.refundMoney();
}
/**
* 申请 - 延迟到子类实现
*/
abstract void apply();
/**
* 公共的审核方法
*/
final void verify() {
System.out.println("触发公共的审核逻辑");
}
/**
* 公共的退款方法
*/
final void refundMoney() {
System.out.println("触发公共的退款逻辑");
}
/**
* 钩子方法 - 是否需要审核
*
* @return boolean
*/
protected boolean needVerify() {
return true;
}
}
2、编写具体实现类
/**
* 用户申请退款实现类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/28
*/
public class UserRefund extends AbstractRefund {
/**
* 申请差异化,子类自己实现
*/
void apply() {
System.out.println("触发用户申请退款逻辑");
}
}
/**
* 后台运营申请退款实现类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/28
*/
public class AdminRefund extends AbstractRefund {
/**
* 默认需要审核(想要动态判断的话,可以从nacos等配置中心取)
*/
private boolean needVerify = true;
/**
* 构造方法判断是否需要审核
*
* @param needVerify 需要验证
*/
public AdminRefund(boolean needVerify) {
this.needVerify = needVerify;
}
/**
* 申请差异化,子类自己实现
*/
void apply() {
System.out.println("触发后台运营申请退款逻辑");
}
/**
* 钩子方法 - 是否需要审核
*
* @return boolean
*/
@Override
protected boolean needVerify() {
return this.needVerify;
}
}
3、编写测试类
/**
* 测试模板模式
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class TemplateTest {
@Test
public void testUserRefund() {
System.out.println("测试 用户退款 开始\n");
AbstractRefund userRefund = new UserRefund();
userRefund.doRefund();
System.out.println("\n测试 用户退款 结束");
}
@Test
public void testAdminRefund_NeedVerify() {
System.out.println("测试 后台运营退款(需要审核) 开始\n");
AbstractRefund adminRefund = new AdminRefund(true);
adminRefund.doRefund();
System.out.println("\n测试 后台运营退款(需要审核) 结束");
}
@Test
public void testAdminRefund_NotNeedVerify() {
System.out.println("测试 后台运营退款(不需要审核) 开始\n");
AbstractRefund adminRefund = new AdminRefund(false);
adminRefund.doRefund();
System.out.println("\n测试 后台运营退款(不需要审核) 结束");
}
}
4、测试结果
①执行testUserRefund
测试 用户退款 开始
触发用户申请退款逻辑
触发公共的审核逻辑
触发公共的退款逻辑
测试 用户退款 结束
②执行testAdminRefund_NeedVerify
测试 后台运营退款(需要审核) 开始
触发后台运营申请退款逻辑
触发公共的审核逻辑
触发公共的退款逻辑
测试 后台运营退款(需要审核) 结束
②执行testAdminRefund_NotNeedVerify
测试 后台运营退款(不需要审核) 开始
触发后台运营申请退款逻辑
触发公共的退款逻辑
测试 后台运营退款(不需要审核) 结束
实现要点
模板模式实现要点如下:
1、抽象出公共的部分为父类或接口。例子中为:AbstractRefund。
2、定义一个操作中的算法的骨架。例子中为:AbstractRefund#doRefund。
3、将一些步骤延迟到子类中。例子中为:AdminRefund和UserRefund。
总结
模板模式是一种行为型设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。