荐 【设计模式】职责链模式:如果第三方短信平台挂了怎么办?
任何傻瓜都能写出计算机可以理解的代码。好的程序员能写出人能读懂的代码”—— Martin Fowler
锅从天上来
风和日丽,我还是和往常一样在自己的座位上写着bug,听着小曲,十分惬意,心里还想着,好久没写博客了,最近也没有什么素材,正当我发愁的时候,素材自动送上门了,又可以写博客了。
测试小哥哥在禅道给我提了一个bug:发送短信验证成功,但是手机一直收不到短信验证码,重试了很多次都不行
。我靠,还能这操作?吓得我赶紧去服务器上捞了日志,查看日志之后发现:原来是短信服务商出现问题了,我们连不上短信服务商,所以导致短信发不出去,然后我就将这个bug直接按外部原因点了解决。
可惜啊,后来产品知道了这个消息之后,他偷偷的申请了两家短信运营商,加上正在使用的这一家,一共是三家,产品给出了一个新的需求:发送短信验证码的时候如果连不上短信运营商,那么就直接换一家继续发,直到将短信发出去为止。
哎,又得加班把这个需求搞定了,一共三个短信运营商,发送短信验证码时,先找到第一个运营商,如果第一个运营商发送失败,那么找到第二个运营商进行发送,如果第二个运营商发送成功,则停止操作,如果第二个运营商发送失败,继续往下找到第三个运营商进行发送,如果三个运行商都发送失败,那么发送邮件告诉运营人员。
大致需求就只这样,如果是你?你会怎么处理这个需求呢?大家可以先思考一下,然后再参考一下我下面的解决思路,可以对比一下。
话不多说,我们正式开始吧!
书到用时方恨少,这个时候知道多读书的好处了吧,下面就是我的showtime!
什么是职责链模式?
责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。(百度百科)
简单来说就是再职责链模式中有很多的处理器,这些处理器依次处理某一个请求,A处理器处理完交给处理器B,处理器B处理完交给处理器C,直到有处理器能够处理这个请求为止。这么一看我们短信的这个需求是不是就可以通过职责链模式来呢?答案是肯定的。
我们一起来看看职责链模式的使用方法
链表实现职责链模式
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler
* @Author: 流星007
* @Description: 处理器抽象父类
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public abstract class Handler {
/**
* 下一个处理器
*/
protected Handler nextHandler = null;
/**
* 设置下一个处理器
* @param nextHandler
*/
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
/**
* 处理器处理请求
*/
public abstract void handler();
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler1
* @Author: 流星007
* @Description: 处理器1
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler1 extends Handler {
@Override
public void handler() {
System.out.println("这是第一个handler,无法解决此问题,请求下一个处理器处理");
boolean flag = false;
if(flag){
return ;
}
if(!flag && nextHandler != null){
nextHandler.handler();
}
}
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler2
* @Author: 流星007
* @Description: 处理器2
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler2 extends Handler {
@Override
public void handler() {
boolean flag = false;
System.out.println("这是第二个handler,无法解决此问题,请求下一个处理器处理");
if(flag){
return ;
}
if(!flag && nextHandler != null){
nextHandler.handler();
}
}
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler3
* @Author: 流星007
* @Description: 处理器3
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler3 extends Handler {
@Override
public void handler() {
boolean flag = true;
System.out.println("这是第三个handler,问题解决,无需在往下执行");
if(flag){
return ;
}
if(!flag && nextHandler != null){
nextHandler.handler();
}
System.out.println("执行结束,没有处理器能够解决这个请求");
}
}
package com.liuxing.chain;
import com.liuxing.handler.Handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.chain
* @ClassName: ChainHandler
* @Author: 流星007
* @Description: 处理器链
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class ChainHandler {
//第一个处理器
private Handler firstHandler;
//最后一个处理器
private Handler endHandler;
/**
* 添加处理器
* @param handler
*/
public void addHandler(Handler handler){
//将当前处理器的下一个处理器设置为null,这一步也可以省略
handler.setNextHandler(null);
//判断是不是第一个处理器,如果是第一个处理器,那么将firstHandler和endHandler都设置为:handler
if(firstHandler == null ){
firstHandler = handler;
endHandler = handler;
return ;
}
//如果不是第一个处理器,那么将当前处理器添加到之前最后一个处理器的下一个处理器中
endHandler.setNextHandler(handler);
//将最后一个处理器修改为当前添加的这个处理器
endHandler = handler;
}
/**
* 开始执行handler
*/
public void handler(){
if(firstHandler == null ){
return ;
}
firstHandler.handler();
}
}
package com.liuxing.test;
import com.liuxing.chain.ChainHandler;
import com.liuxing.handler.Handler1;
import com.liuxing.handler.Handler2;
import com.liuxing.handler.Handler3;
public class HandlerTest {
public static void main(String[] args) {
ChainHandler chainHandler = new ChainHandler();
chainHandler.addHandler(new Handler1());
chainHandler.addHandler(new Handler2());
chainHandler.addHandler(new Handler3());
chainHandler.handler();
}
}
这就是职责链模式的demo,有一个抽象父类:Handler(处理器抽象父类);三个子类:Handler1、Handler2、Handler3;重写父类中的handler方法,还需要一个处理器链:ChainHandler,处理器链中包含首尾两个处理器,一个添加处理器的方法,一个执行handler的方法,我们一起来看看这个demo的执行结果:
这是第一个handler,无法解决此问题,请求下一个处理器处理
这是第二个handler,无法解决此问题,请求下一个处理器处理
这是第三个handler,问题解决,无需在往下执行
Process finished with exit code 0
我们发现执行到第三个处理器的时候就不再往下执行了。
职责链模式相信大家都知道怎么使用了,我也相信大家也应该知道短信的需求怎么改造了吧,短信的代码改造这里我就不写了,大家感性的话可以自己研究一下,照葫芦画瓢就行了,很简单。
那这篇博客是不是就这样结束了呢?当然不是,重点才刚刚开始。
上面的职责链模式让人看起来很别扭,那是因为还没有优化过,我们发现再三个子类中都需要调用下一个处理器对不对,这样是不是比较麻烦,如果有人再添加处理器的时候忘记调用下一个处理器呢?bug是不是就来了,然后你就需要加班了,所以这种事情必须要扼杀在摇篮里,我们直接不在子类中调用下一个处理器,我们把调用下一个处理器放到抽象父类中,让他统一处理,就能完美解决了。
请看代码
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler
* @Author: 流星007
* @Description: 处理器抽象父类
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public abstract class Handler {
/**
* 下一个处理器
*/
protected Handler nextHandler = null;
/**
* 设置下一个处理器
* @param nextHandler
*/
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public final void handler(){
boolean flag = doHandler();
if(!flag && nextHandler!= null){
nextHandler.handler();
}
}
/**
* 处理器处理请求
*/
protected abstract boolean doHandler();
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler1
* @Author: 流星007
* @Description: 处理器1
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler1 extends Handler {
@Override
public boolean doHandler() {
System.out.println("这是第一个handler,无法解决此问题,请求下一个处理器处理");
return false;
}
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler2
* @Author: 流星007
* @Description: 处理器2
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler2 extends Handler {
@Override
public boolean doHandler() {
System.out.println("这是第二个handler,无法解决此问题,请求下一个处理器处理");
return false;
}
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler3
* @Author: 流星007
* @Description: 处理器3
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler3 extends Handler {
@Override
public boolean doHandler() {
boolean flag = true;
System.out.println("这是第三个handler,问题解决,无需在往下执行");
if(flag){
return true;
}
System.out.println("执行结束,没有处理器能够解决这个请求");
return false;
}
}
其他代码不变,我们发现,调用下一个处理器的代码被移动了抽象父类处理器Handler中,自立只需要安安心心的处理自己的逻辑即可,是不是降低的bug的产生率?
这里有个小知识点,大家直到我在抽象父类:Handler中为什么将handler();设置为final吗?知道的可以卸载评论区哦。
使用数组实现职责链模式
这种实现方式比上面那种基于链表的实现方式更为简单,也更容易理解,废话不多说,直接上代码
package com.liuxing.handler;
/**
* @ProjectName: demo
* @Package: com.liuxing.handler
* @ClassName: IHandler
* @Author: 流星007
* @Description: 处理器接口
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Date: 2020/7/13 17:17
* @Version: 1.0
*/
public interface IHandler {
boolean handler();
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler1
* @Author: 流星007
* @Description: 处理器1
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler1 implements IHandler {
@Override
public boolean handler() {
System.out.println("这是第一个handler,无法解决此问题,请求下一个处理器处理");
return false;
}
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler2
* @Author: 流星007
* @Description: 处理器2
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler2 implements IHandler {
@Override
public boolean handler() {
System.out.println("这是第二个handler,无法解决此问题,请求下一个处理器处理");
return false;
}
}
package com.liuxing.handler;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.handler
* @ClassName: Handler3
* @Author: 流星007
* @Description: 处理器3
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class Handler3 implements IHandler{
@Override
public boolean handler() {
boolean flag = true;
System.out.println("这是第三个handler,问题解决,无需在往下执行");
if(flag){
return true;
}
System.out.println("执行结束,没有处理器能够解决这个请求");
return false;
}
}
package com.liuxing.chain;
import com.liuxing.handler.Handler;
import com.liuxing.handler.IHandler;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @ProjectName: handler-of-responsibility-pattern
* @Package: com.liuxing.chain
* @ClassName: ChainHandler
* @Author: 流星007
* @Description: 处理器链
* csdn:https://blog.csdn.net/qq_33220089
* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
* @Version: 1.0
*/
public class ChainHandler {
/**
* 所有的处理器
*/
private List<IHandler> list = new ArrayList<IHandler>();
/**
* 添加处理器
* @param handler
*/
public void addHandler(IHandler handler){
list.add(handler);
}
/**
* 开始执行handler
*/
public void handler(){
if(CollectionUtils.isEmpty(list)){
return ;
}
for(IHandler handler: list){
if(handler.handler()){
return;
}
}
}
}
package com.liuxing.test;
import com.liuxing.chain.ChainHandler;
import com.liuxing.handler.Handler1;
import com.liuxing.handler.Handler2;
import com.liuxing.handler.Handler3;
public class HandlerTest {
public static void main(String[] args) {
ChainHandler chainHandler = new ChainHandler();
chainHandler.addHandler(new Handler1());
chainHandler.addHandler(new Handler2());
chainHandler.addHandler(new Handler3());
chainHandler.handler();
}
}
好了,代码改造完成,这种方式相对第一种方式来说,理解起来更加的容易,因为ArrayList是有序的,所以循环执行的时候按照先添加的先执行,想要控制处理器的执行顺序,只需要控制list的添加顺序即可,简单方便。
指责连模式的变异模式
职责链模式再开发过程中渐渐的派生出一个新的变异模式,什么样的模式呢?正常职责链模式:只要有处理器能够处理这个请求,就结束当前流程,而变异版本就是不管当前处理器能不能处理这个请求,都要依次往下执行,直到所有的处理器都被执行。这种变异模式再游戏中的敏感词过滤中比较常见。
职责链模式应用场景
1.过滤游戏中的敏感词汇
2.servlet中的handler也是采用了职责链模式哦,感兴趣的小伙伴可以去看看。
3.较多的switch-case也能使用指责连模式进行优化哦。
总结
什么是指责连模式?
责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。(百度百科)
简单来说就是再职责链模式中有很多的处理器,这些处理器依次处理某一个请求,A处理器处理完交给处理器B,处理器B处理完交给处理器C,直到有处理器能够处理这个请求为止。
职责链变异模式
与正常的职责链模式相比,它需要执行完所有的处理器,再游戏敏感词过滤中较为常见。
常见的设计模式
【设计模式】工厂模式:你还在使用一堆的if/else创建对象吗?
【设计模式】门面模式:接口就像门面,一眼就能看出你的代码水平
本文地址:https://blog.csdn.net/qq_33220089/article/details/107303971