模板方法模式(Template)
模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。
模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。
业务场景
假设我们现在要实现一个对单据审批功能,有请假申请、加班申请。他们的算法逻辑都一样,只有同意或拒绝后的操作不一样。你先不要为什么是这些功能,你只要知道我们现在有这么多的申请功能,然后有这么多申请的逻辑需要你实现。怎么做,是分别再各个模块的service里面实现一边吗?
注意,他们有一样的算法逻辑。接下来看怎么实现。其实实现起来很简单。
/**
* 工作流处理类:模板方法
*/
public abstract class WorkFlowService{
/**
* 审批单据工作流:同意/拒绝
*
* @param tenantId 租户id
* @param id 单据主键
* @param node 流程节点:最后节点/流程中节点
* @param approveResult 审批结果:同意/拒绝
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void workFlowChangeStatus(Long tenantId, Long id, String node, String approveResult) {
// 判断申请记录是否存在
check(tenantId, id);
// 最后节点
if (ApproveResult.END_NODE.equals(node)) {
// 同意
if (ApproveResult.APPROVE.value().equals(approveResult)) {
approve(tenantId, id);
}
// 拒绝
if (ApproveResult.REJECT.value().equals(approveResult)) {
reject(tenantId, id);
}
}
// 流程中间节点
if (ApproveResult.PROCESS_NODE.equals(node)) {
// 中间节点:拒绝
if (ApproveResult.REJECT.value().equals(approveResult)) {
reject(tenantId, id);
}
}
}
/**
* 校验
*/
protected abstract void check(Long tenantId, Long id);
/**
* 拒绝操作
*/
protected abstract void reject(Long tenantId, Long id);
/**
* 同意操作
*/
protected abstract void approve(Long tenantId, Long id);
}
check reject approve是三个勾子方法,也就是需要用户自定以的逻辑实现方法,而workFlowChangeStatus就是模板方法了,我们可以看到里面的逻辑不跟任何一个service相依赖,是通用的。
/**
* 请假申请
*/
@Service
public class LeaveApplyService extends WorkFlowService {
@Override
protected void reject(Long tenantId, Long id) {
// todo 拒绝请假逻辑
}
@Override
protected void approve(Long tenantId, Long id) {
// todo 同意请假逻辑
}
}
/**
* 加班申请
*/
@Service
public class OvertimeApplyService extends WorkFlowService {
@Override
protected void reject(Long tenantId, Long id) {
// todo 拒绝加班逻辑
}
@Override
protected void approve(Long tenantId, Long id) {
// todo 同意加班逻辑
}
}
上面我们是不是已经写好了Service相关实现,也就是模板方法的基本思想的实现,也就是通过继承来实现的。
接下来是Controller。那我们是不是要每个Service方法都写一个对应的Controller,再写一遍对应的接口。我们有更简便的实现,既然每个service都继承了模板方法,那我们可以写一个通用的Controller,通过传入不同的类型来调用不同service,这里使用简单工厂方法的思想来实现。
/**
* 工作流入口
*/
@RestController
@RequestMapping("/work-flow")
public class ContractWorkFlowController {
@Autowired
private WorkFlowDispatcher workFlowDispatcher;
/**
* 工作流审批调用接口,根据操作类型 optional,执行不同操作{@link WorkFlowOptionalType}
*
* @param tenantId 租户id
* @param optional 操作类型
* @param params 工作流的流程变量
*/
@Permission(level = ResourceLevel.ORGANIZATION)
@ApiOperation(value = "工作流审批操作接口")
@GetMapping(value = "/workflow/{optional}")
public void workFlowOptional(@PathVariable("organizationId") Long tenantId,
@PathVariable("optional") String optional,
WorkFlowParams params) {
params.setTenantId(tenantId);
workFlowDispatcher.invokeService(optional, params);
}
}
workFlowDispatcher这个类就是简单工厂的实现,根据单据类型documentType来决定调用哪个service, 根据操作类型optional来选择审批操作(流程中/流程结果)
/**
* 工作流分发
*/
@Service
public class WorkFlowDispatcher {
@Autowired
private LeaveApplyService leaveApplyService;
@Autowired
private OvertimeApplyService overtimeApplyService;
/**
* 调用service,执行审批操作
*
* @param optional 审批操作类型{@link WorkFlowOptionalType}
* @param params
*/
public void invokeService(String optional, WorkFlowParams params) {
Long tenantId = params.getTenantId();
Long documentId = params.getDocumentId();
String documentType = params.getDocumentType();
String approveResult = params.getApproveResult();
IWorkFlowService workFlowService = chooseService(documentType);
switch (optional) {
// 工作流:审批结果
case WorkFlowOptionalType.RESULT:
workFlowService.workFlowChangeStatus(tenantId, documentId, ApproveResult.END_NODE, approveResult);
break;
// 工作流:审批中节点
case WorkFlowOptionalType.PROCESS:
workFlowService.workFlowChangeStatus(tenantId, documentId, ApproveResult.PROCESS_NODE, approveResult);
break;
default:
throw new IllegalArgumentException("error.workFlow.optional.illegal");
}
}
/**
* 根据单据类型,选择对应的service
*
* @param documentType {@link WorkFlowDocumentTypeEnum}
* @return
*/
private IWorkFlowService chooseService(String documentType) {
if (WorkFlowDocumentTypeEnum.LEAVEAPPLY.value().equals(documentType)) {
return leaveApplyService;
} else if (WorkFlowDocumentTypeEnum.OVERTIMEAPPLY.value().equals(documentType)) {
return overtimeApplyService;
} else {
throw new IllegalArgumentException("error.workFlow.documentType.illegal");
}
}
}
这样做有什么用呢,直接写几个Controller也能搞定。这样写能提高代码的可维护性,当逻辑发生修改时,只需要改这一个类。如果你每个service都重复实现一个对应的Controller,如果要变更,每个地方都需要改。你再想想哪种实现会更好,并且,你写那么多Controller都是再做同样的事情,你不觉得是没有必要的重复吗。
本期分享就到这里了,希望你能再能够将设计模式在实际开发中有所运用。如果有疑惑、或者对文章有什么建议欢迎留言交流。
模板方法模式用于定义算法骨架,将不同步骤留给子类实现。在单据审批功能中,如请假、加班申请,虽然审批逻辑相同,但同意或拒绝后的操作不同。通过模板方法,可以避免在每个模块的service中重复实现,提高代码可维护性。Controller通过简单工厂方法调用相应service,减少重复代码,便于逻辑变更时统一修改。
442

被折叠的 条评论
为什么被折叠?



