本篇文章讲解责任链设计模式
责任链模式
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。
这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会
把相同的请求传给下一个接收者,依此类推。
需求
在公司流程处理业务中,有不同的处理流程节点,在不同的节点需要发送不同的短信,用来通知下一个节点的处置人。 1发起->2审核->3处置->4结果审核->完成,每个环节还可以有退回到上一个节点的功能,而且不同的地区还可能有其他的流程节点。一开始产品只提出审核和处置两个节点需要发送短信,因此一开始的代码是这样写的。
public class WarningSmsHandler {
public void sendSms() {
//处理发送短信逻辑
if(是否是审核完成) {
//查询处置人,设置短信内容,发送短信
} else if(是否是处置完成) {
//查询结果审核人,设置短信内容,发送短信
}
}
}
随着时间推移,产品又提出需要在发起环节发送短信,通知审核人。这个时候可以选择修改原来的WarningSmsHandler类,这样现在实现起来是比较快的,但是这样也会给以后带来一些问题: 1、随着越来越多节点的短信发送需求,后面会不断的在这个类加代码,违反了单一职责原则。 2、以后加一个节点的短信,删除一个节点的短信,都需要改WarningSmsHandler类的代码,违背开闭原则。
所以必须思考下如何选择一个周全的方案,避免这些问题。 回到需求,短信发送是上一个节点发送给下一个节点,一般只发送给下一个节点的人。这里想到使用责任链模式,将各个节点发送短信的逻辑进行拆分,单一职责。
根据责任链模式实现该需求
1、定义统一请求类
@Data
public class WarningSmsHandlerRequest{
//通报id
private Long warningId;
//下一个通报状态
private WarningStateEnum nextWarningState;
//下一个通报处置人类型
private WarningHandleUnitEnum warningHandleUnitEnum;
//附加参数
private List<String> attachmentParam;
//短信模版id 有些短信厂商需要模版
private String templateId;
}
2、定义统一处理结果类
@Data
public class WarningSmsHandlerResult {
//发送成功的手机号列表
private List<String> mobiles =new ArrayList<>();
//发送是否成功
private Boolean success;
}
2、定义请求处理接口
/**
* 短信处理器接口
*/
public interface SmsHandler {
//当前接口是否支持处理
boolean support(WarningSmsHandlerRequest request);
//处理逻辑
void handleSms(WarningSmsHandlerRequest request, WarningSmsHandlerResult result);
}
一个具体请求处理器实现-审核环节短信处理器
/**
* 审核环节短信发送逻辑
*/
@Component
public class WarningAuditSmsHandler implements SmsHandler {
@Override
public boolean support(WarningSmsHandlerRequest request) {
return request.getNextWarningState().equals(WarningStatusEnum.WAIT_AUDIT);
}
@Override
public void handleSms(WarningSmsHandlerRequest request, WarningSmsHandlerResult result) {
//处理审核短信
System.out.println("处理审核短信发送逻辑");
}
}
一个具体请求处理器实现-处置环节短信处理器
/**
* 处置环节短信发送逻辑
*/
@Component
public class WarningHandleSmsHandler implements SmsHandler {
@Override
public boolean support(WarningSmsHandlerRequest request) {
return request.getNextWarningState().equals(WarningStatusEnum.HANDLE);
}
@Override
public void handleSms(WarningSmsHandlerRequest request, WarningSmsHandlerResult result) {
//处理审核短信
System.out.println("处理处置短信发送逻辑");
}
}
处理器写好了,怎么让他们一起串起来了? 一般的写法是每个处理器有一个设置下一个处器的方法(setNext),指定下次执行的处理器。 这种写法在有顺序要求的链路处理中比较常用,在以后修改或新增处理器都需要修改setNext方法。 在本次案例中,每个节点都会调用这个发送短信流程,每个处理器都有一个support方法,每次都会根据当前请求过滤出需要处理的处理器。
构造处理器调用链接口
public interface WarningSmsHandlerInvocation {
WarningSmsHandlerResult invoke(WarningSmsHandlerRequest request);
}
构造处理器调用链接口实现
@Component
@Setter
public class WarningSmsHandlerInvocationImpl implements WarningSmsHandlerInvocation {
//通过spring注入所有SmsHandler类型的bean
@Autowired
private List<SmsHandler> smsHandlers;
@Override
public WarningSmsHandlerResult invoke(WarningSmsHandlerRequest request) {
WarningSmsHandlerResult result = new WarningSmsHandlerResult();
//依次调用所有匹配当前请求的处理器
for (SmsHandler smsHandler : smsHandlers) {
if (smsHandler.support(request)) {
smsHandler.handleSms(request, result);
}
}
return result;
}
}
使用写好的处理链调用器进行测试
@Component
public class WarningSmsHandlerClient {
@Autowired
private WarningSmsHandlerInvocation invocation;
public void testSmsSend() {
WarningSmsHandlerRequest request = new WarningSmsHandlerRequest();
request.setNextWarningState(WarningStatusEnum.WAIT_AUDIT);
WarningSmsHandlerResult result = invocation.invoke(request);
System.out.println(result);
}
}
如果需要新增一个处理器,则只要实现WarningAuditSmsHandler接口就可以了。
总结
通过使用责任链模式,可以降低业务代码的耦合度,提升整体的可扩展性和可维护性。
- 每个具体处理器只要处理自己负责的业务,符合单一职责原则
- 新增,修改,删除,都不会修改调用器的逻辑
以上全部内容,如果更好的设计欢迎交流探讨。