返回顶部
首页 > 资讯 > 前端开发 > JavaScript >责任链设计模式的实现方法是什么
  • 604
分享到

责任链设计模式的实现方法是什么

2024-04-02 19:04:59 604人浏览 薄情痞子
摘要

本篇内容介绍了“责任链设计模式的实现方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!责任链设计模式

本篇内容介绍了“责任链设计模式的实现方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

责任链设计模式

模式定义

请求在一个链条上处理,链条上的受理者处理完毕之后决定是继续往后传递还是中断当前处理流程。

适用场景

适用于多节点的流程处理,每个节点完成各自负责的部分,节点之间不知道彼此的存在,比如 OA 的审批流,JAVA WEB 开发中的 Filter  机制。

举一个生活中的例子,笔者之前租房的时候遇到了所谓的黑中介,租的时候感觉自己是上帝,但是坏了东西找他修的时候就像个孙子一样。

中介让我找门店客服,门店客服又让我找房东,房东又让我找她家老公,最终好说歹说才把这事了了(租房一定要找正规中介)。

实践经验

笔者目前所做的业务是校园团餐的聚合支付,业务流程很简单:

  • 学生打开手机付款码支付。

  • 食堂大妈使用机具扫付款码收款。

大学食堂有个背景是这样的,食堂有补贴,菜品比较便宜,所以学校是不愿意让社会人士去学校食堂消费的,鉴于此,我们在支付之前加了一套是否允许支付的检验逻辑。

大体如下:

  • 某档口只允许某类用户用户消费,比如教师档口只允许教师消费,学生档口不允许校外用户消费。

  • 某个档口一天只允许某类用户消费几次,比如教师食堂一天只允许学生消费一次。

  • 是否允许非清真学生消费,比如某些清真餐厅,是不允许非清真学生消费的。

针对这几类情况我建立了三类过滤器,分别是:

  • SpecificCardUserConsumeLimitFilter:按用户类型判断是否允许消费。

  • DayConsumeTimesConsumeLimitFilter:按日消费次数判断是否允许消费。

  • MuslimConsumeLimitFilter:非清真用户是否允许消费。

判断逻辑是先通过 SpecificCardUserConsumeLimitFilter 判断当前用户是否可以在此档口消费。

如果允许继续由 DayConsumeTimesConsumeLimitFilter 判断当天消费次数是否已用完;如果未用完继续由  MuslimConsumeLimitFilter 判断当前用户是否满足清真餐厅的就餐条件,前面三条判断,只要有一个不满足就提前返回。

部分代码如下:

public boolean canConsume(String uid,String shopId,String supplierId){     //获取用户信息,用户信息包含类型(student:学生,teacher:老师,unknown:未知用户)、名族(han:汉族,mg:蒙古族)     UserInfo userInfo = getUserInfo(uid);     //获取消费限制信息,限制信息包含是否允许非清真消费、每种类型的用户是否允许消费以及允许消费的次数    ConsumeConfigInfo consumeConfigInfo = getConsumeConfigInfo(shopId,supplierId)        // 构造消费限制过滤器链条     ConsumeLimitFilterChain filterChain = new ConsumeLimitFilterChain();     filterChain.addFilter(new SpecificCardUserConsumeLimitFilter());     filterChain.addFilter(new DayConsumeTimesConsumeLimitFilter());     filterChain.addFilter(new MuslimConsumeLimitFilter());     boolean checkResult = filterChain.doFilter(filterChain, schoolMemberInfo, consumeConfigInfo);      //filterChain.doFilter方法    public boolean doFilter(ConsumeLimitFilterChain filterChain,UserInfo userInfo,              ConsumeConfigInfo consumeConfigInfo ){         //迭代调用过滤器         if(index<filters.size()){             return filters.get(index++).doFilter(filterChain, userInfo, consumeConfigInfo);         }     }      //SpecificCardUserConsumeLimitFilter.doFilter方法      public boolean doFilter(ConsumeLimitFilterChain filterChain,UserInfo userInfo,              ConsumeConfigInfo consumeConfigInfo ){                 //获取某一类型的消费限制,比如student允许消费,unknown不允许消费         CardConsumeConfig cardConsumeConfig = findSuitCardConfig(userInfo, consumeConfigInfo);          // 判断当前卡用户是否允许消费         if (consumeCardConfig != null) {             if ((!CAN_PAY.equals(cardConsumeConfig .getEnabledPay()))) {                 return false;             }         }                  //其余情况,继续往后传递             return filterChain.doFilter(filterChain, memberInfo, consumeConfig);         }      //DayConsumeTimesConsumeLimitFilter.doFilter方法      public boolean doFilter(ConsumeLimitFilterChain filterChain,UserInfo userInfo,              ConsumeConfigInfo consumeConfigInfo ){                 //获取某一类型的消费限制,比如student可以消费2次         CardConsumeConfig cardConsumeConfig = findSuitCardConfig(userInfo, consumeConfigInfo);                  //获取当前用户今天的消费次数                 int consumeCnt = getConsumeCnt(userInfo)                 if(consumeCnt >= cardConsumeConfig.getDayConsumeTimesLimit()){                     return false;                 }                  //其余情况,继续往后传递                 return filterChain.doFilter(filterChain, memberInfo, consumeConfig);         }

总结:将每种限制条件的判断逻辑封装到了具体的 Filter 中,如果某种限制条件的逻辑有修改不会影响其他条件,如果需要新加限制条件只需要重新构造一个  Filter 织入到 FilterChain 上即可。

策略设计模式

模式定义

定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换。

适用场景

主要是为了消除大量的 if else  代码,将每种判断背后的算法逻辑提取到具体的策略对象中,当算法逻辑修改时对使用者无感知,只需要修改策略对象内部逻辑即可。

这类策略对象一般都实现了某个共同的接口,可以达到互换的目的。

实践经验

笔者之前有个需求是用户扫码支付以后向档口的收银设备推送一条支付消息,收银设备收到消息以后会进行语音播报,逻辑很简单,就是调用推送平台推送一条消息给设备即可。

但是由于历史原因,某些设备对接的推送平台是不一样的,A 类设备优先使用信鸽推送,如果失败了需要降级到长轮询机制,B  类设备直接使用自研的推送平台即可。

还有个现状是 A 类和 B 类的消息格式是不一样的(不同的团队开发,后期被整合到一起)。

鉴于此,我抽象出 PushStrategy 接口,其具体的实现有 iotPushStrategy 和  XingePushStrategy,分别对应自研推送平台的推送策略和信鸽平台的推送策略,使用者时针对不同的设备类型使用不同的推送策略即可。

部分代码如下:

     public CallResult push(AppDeviceVO deviceVO, Object content); }  IotPushStrategy implements PushStrategy{              public CallResult push(AppDeviceVO deviceVO, Object content){             //创建自研推送平台需要的推送报文             Message message = createPushMsg(deviceVO,content);              //调用推送平台推送接口             IotMessageService.pushMsg(message);         } }  XingePushStrategy implements PushStrategy{              public CallResult push(AppDeviceVO deviceVO, Object content){             //创建信鸽平台需要的推送报文             JSONObject jsonObject = createPushMsg(content);              //调用推送平台推送接口             if(!XinggePush.pushMsg(message)){                 //降级到长轮询                 ...             }         } }   MessagePushService{     pushMsg(AppDeviceVO deviceVO, Object content){         if(A设备){             XingePushStrategy.push(deviceVO,content);         } else if(B设备){             IotPushStrategy.push(deviceVO,content);         }     } }

总结:将每种通道的推送逻辑封装到了具体的策略中,某种策略的变更不会影响其他策略,由于实现了共同接口,所以策略可以互相替换,对使用者友好。

比如 Java ThreadPoolExecutor 中的任务拒绝策略,当线程池已经饱和的时候会执行拒绝策略,具体的拒绝逻辑被封装到了  RejectedExecutionHandler 的 rejectedExecution 中。

模板设计模式

模式定义

模板的价值就在于骨架的定义,骨架内部将问题处理的流程已经定义好,通用的处理逻辑一般由父类实现,个性化的处理逻辑由子类实现。

比如炒土豆丝和炒麻婆豆腐,大体逻辑都是:

  • 切菜

  • 放油

  • 炒菜

  • 出锅

1,2,4 都差不多,但是第 3 步是不一样的,炒土豆丝得拿铲子翻炒,但是炒麻婆豆腐得拿勺子轻推,否则豆腐会烂(疫情宅在家,学了不少菜)。

使用场景

不同场景的处理流程,部分逻辑是通用的,可以放到父类中作为通用实现,部分逻辑是个性化的,需要子类去个性实现。

实践经验

还是接着之前语音播报的例子来说,后期我们新加了两个需求:

  • 消息推送需要增加 trace。

  • 有些通道推送失败需要重试。

所以现在的流程变成了这样:

  • trace 开始。

  • 通道开始推送。

  • 是否允许重试,如果允许执行重试逻辑。

  • trace 结束。

其中 1 和 4 是通用的,2 和 3 是个性化的,鉴于此我在具体的推送策略之前增加了一层父类的策略,将通用逻辑放到了父类中。

修改后的代码如下:

abstract class AbstractPushStrategy implements PushStrategy{     @Override     public CallResult push(AppDeviceVO deviceVO, Object content) {         //1.构造span         Span span = buildSpan();         //2.具体通道推送逻辑由子类实现         CallResult callResult = doPush(deviceVO, content);          //3.是否允许重试逻辑由子类实现,如果允许执行重试逻辑         if(!callResult.isSuccess() && canRetry()){             doPush(deviceVO, content);         }          //4.trace结束         span.finish()      }      //具体推送逻辑由子类实现     protected abstract CallResult doPush(AppDeviceVO deviceDO, Object content) ;      //是否允许重试由子类实现,有些通道之前没有做消息排重,所有不能重试     protected abstract boolean canRetry(CallResult callResult);  }  XingePushStrategy extends AbstractPushStrategy{     @Override     protected CallResult doPush(AppDeviceVO deviceDO, Object content) {         //执行推送逻辑     }      @Override     protected boolean canRetry(CallResult callResult){         return false     } }

总结:通过模板定义了流程,将通用逻辑放在父类实现,减少了重复代码,个性化逻辑由子类自己实现,子类间修改代码互不干扰也不会破坏流程。

观察者设计模式

模式定义

顾名思义,此模式需要有观察者(Observer)和被观察者(Observable)两类角色。

当 Observable 状态变化时会通知 Observer,Observer 一般会实现一类通用的接口。

比如 java.util.Observer,Observable 需要通知 Observer 时,逐个调用 Observer 的 update  方法即可,Observer 的处理成功与否不应该影响 Observable 的流程。

使用场景

一个对象(Observable)状态改变需要通知其他对象,Observer 的存在不影响 Observable 的处理结果,Observer 的增删对  Observable 无感知。

比如 kafka 的消息订阅,Producer 发送一条消息到 Topic,至于是 1 个还是 10 个 Consumer 订阅这个  Topic,Producer 是不需要关注的。

实践经验

在责任链设计模式那块我通过三个 Filter 解决了消费限制检验的问题,其中有一个 Filter  是用来检验消费次数的,我这里只是读取用户的消费次数,那么消费次数的累加是怎么完成的呢?

其实累加这块就用到了观察者模式,具体来讲是这样,当交易系统收到支付成功回调时会通过 spring 的事件机制发布“支付成功事件”。

这样负责累加消费次数和负责语音播报的订阅者就会收到“支付成功事件”,进而做各自的业务逻辑。

画个简单的图描述一下:

责任链设计模式的实现方法是什么

代码结构大体如下:

 PayCallBackController implements ApplicationContextAware {      private ApplicationContext applicationContext;      //如果想获取applicationContext需要实现ApplicationContextAware接口,Spring容器会回调setApplicationContext方法将applicationContext注入进来     @Override     public void setApplicationContext(ApplicationContext applicationContext)             throws BeansException {         this.applicationContext = applicationContext;     }      @RequestMapping(value = "/pay/callback.do")      public View callback(httpservletRequest request){         if(paySuccess(request){             //构造支付成功事件             PaySuccessEvent event = buildPaySuccessEvent(...);             //通过applicationContext发布事件,从而达到通知观察者的目的             this.applicationContext.publishEvent(event);         }      } }  public class VoiceBroadcastHandler implements ApplicationListener<PaySuccessEvent>{     @Override     public void onApplicationEvent(PaySuccessEvent event) {         //语音播报逻辑     } }  //其他处理者的逻辑类似

总结:观察者模式将被观察者和观察者之间做了解耦,观察者存在与否不会影响被观察者的现有逻辑。

装饰器设计模式

模式定义

装饰器用来包装原有的类,在对使用者透明的情况下做功能的增强,比如 Java 中的 BufferedInputStream 可以对其包装的  InputStream 做增强,从而提供缓冲功能。

使用场景

希望对原有类的功能做增强,但又不希望增加过多子类时,可以使用装饰器模式来达到同样的效果。

实践经验

笔者之前在推动整个公司接入 trace 体系,因此也提供了一些工具来解决 trace 的自动织入和上下文的自动传递。

为了支持线程间的上下文传递,我增加了 TraceRunnableWrapper  这个装饰类,从而起到将父线程的上下文透传到子线程中,对使用者完全透明。

代码如下:

 public class TraceRunnableWrapper implements Runnable{     //被包装的目标对象     private Runnable task;     private Span parentSpan = null;      public TraceRunnableWrapper(Runnable task) {         //1.获取当前线程的上下文(因为new的时候还没有发生线程切换,所以需要在这里将上下文获取)         //对这块代码感兴趣的可以查看opentracing api         io.opentracing.Scope currentScope = GlobalTracer.get().scopeManager().active();         //2.保存父上下文         parentSpan = currentScope.span();         this.task = task;     }      @Override     public void run() {         //run的时候将父线程的上下文绑定到当前线程         io.opentracing.Scope scope = GlobalTracer.get().scopeManager().activate(parentSpan,false);         task.run();     } }  //使用者 new Thread(new Runnable(){run(...)}).start()替换为new TraceRunnableWrapper(new Runnable(){run(...)}).start()

总结:使用装饰器模式做了功能的增强,对使用者来说只需要做简单的组合就能继续使用原功能。

外观设计模式

模式定义

何为外观,就是对外提供一个统一的入口:

  • 一是可以影藏系统内部的细节。

  • 二是可以降低使用者的复杂度。

比如 springMVC 中的 DispaterServlet,所有的 Controller 都是通过 DispaterServlet 统一暴露。

使用场景

降低使用者的复杂度,简化客户端的接入成本。

实践经验

笔者所在的公司对外提供了一些开放能力给第三方 ISV,比如设备管控、统一支付、对账单下载等能力。

由于分属于不同的团队,所以对外提供的接口形式各异,初期还好,接口不多,ISV 也能接受,但是后期接口多了 ISV 就开始抱怨接入成本太高。

为了解决这一问题,我们在开放接口前面加了一层前端控制器 GatewayController,其实就是我们后来开放平台的雏形。

GatewayController 对外统一暴露一个接口 gateway.do,将对外接口的请求参数和响应参数统一在 GatewayController  做收敛,GatewayController 往后端服务路由时也采用统一接口。

改造前后对比如下图:

责任链设计模式的实现方法是什么

大概代码如下:

使用者: HttpClient.doPost("/gateway.do","{'method':'trade.create','sign':'wxxaaa','timestamp':'15311111111'},'bizContent':'业务参数'")  GatewayController: @RequestMapping("/gateway.do") JSON gateway(HttpServletRequest req){    //1.组装开放请求    OpenRequest openRequest = buildOpenRequest(req);     OpenResponse openResponse = null;    //2.请求路由    if("trade.create".equals(openRequest.getMethod()){        //proxy to trade service by dubbo        openResponse = TradeFacade.execute(genericParam);    } else if("iot.message.push".equals(openRequest.getMethod()){        //proxy to iot service by httpclient         openResponse = HttpClient.doPost('http://iot.service/generic/execute'genericParam);    }     if(openResponse.isSuccess()){         return {"code":"10000","bizContent":openResponse.getResult()};    }else{         return {"code":"20000","bizCode":openResponse.getCode()};    }   }

“责任链设计模式的实现方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: 责任链设计模式的实现方法是什么

本文链接: https://lsjlt.com/news/84509.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 责任链设计模式的实现方法是什么
    本篇内容介绍了“责任链设计模式的实现方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!责任链设计模式...
    99+
    2024-04-02
  • java设计模式中的责任链模式是什么
    本篇文章为大家展示了java设计模式中的责任链模式是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一:模式说明模式定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。...
    99+
    2023-06-22
  • Java实现设计模式之责任链模式
    目录1.什么是责任链模式2.如何实现3.代码实现4.总结1.什么是责任链模式 当一个请求可能需要多个对象中的某个进行处理时,将这些对象连成一条链,并沿者这条链传递该请求,知道有一个对...
    99+
    2024-04-02
  • java设计模式(实战)-责任链模式
    目录一:模式说明二:项目实战三:源代码一:模式说明 模式定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,...
    99+
    2024-04-02
  • Java设计模式中的责任链怎么实现
    本篇内容介绍了“Java设计模式中的责任链怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!责任链模式(Chain of Respons...
    99+
    2023-06-17
  • 什么是责任链模式
    这篇文章主要讲解了“什么是责任链模式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么是责任链模式”吧!前言面试经历大家肯定都有过,但是面试的流程其实跟一种...
    99+
    2024-04-02
  • 详解Java实现设计模式之责任链模式
    目录一、模拟业务需求二、小步小跑的迭代开发三、系统对数据的校验要求四、新建一个抽象类五、子类的实现六、构建责任链和调用七、可维护性八、总结8.1、责任链模式8.2、责任链模式适用的场...
    99+
    2024-04-02
  • Java设计模式之责任链模式
    本文通过图书馆管理系统中,用户名校验、密码校验、需要增加问题,每次都要增加if判断语句,将其改用责任链模式进行链式调用,为了让代码更加的优雅,我们使用之前学过的建造者模式就代码进行改...
    99+
    2024-04-02
  • Java 设计模式之责任链模式及异步责任链详解
    目录一、定义二、普通责任链模式三、异步责任链模式一、定义 责任链模式(Chain of Responsibility Pattern):避免将一个请求的发送者与接受者耦合在一起,让多...
    99+
    2024-04-02
  • Java设计模式之责任链模式详解
    一、前言 各个部门协同合作完成一个任务,每个部门都有各自的职责,一个部门完成后,变回转交给下一个部门,直到所有部门都处理了,这个任务才完成。 将请求与处理解耦。 处理者只需要关注自己...
    99+
    2024-04-02
  • Python设计模式行为型责任链模式
    目录一、责任链模式二、应用场景三、代码示例一、责任链模式 责任链模式,将多个处理方法连接成一条链条,请求将在这条链条上流动直到该链条中有一个节点可以处理该请求。通常这条链条是一个对象...
    99+
    2024-04-02
  • C#设计模式实现之生成器模式和责任链模式
    目录生成器设计类图: 实现代码:优点:用途与缺点:责任链设计类图:实现代码:优点:用途和缺点:总结生成器 生成器模式:封装一个产品的构造过程,并允许按步骤构造。 现又一个...
    99+
    2024-04-02
  • PHP中的责任链模式是什么
    本篇内容介绍了“PHP中的责任链模式是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!责任链模式,属于对象行为型的设计模式。Gof类图及解...
    99+
    2023-06-20
  • java责任链模式怎么实现
    Java中实现责任链模式可以使用以下步骤: 定义一个抽象的处理器(Handler)类,该类包含一个指向下一个处理器的引用和一个处理...
    99+
    2024-02-29
    java
  • Java设计模式之java责任链模式详解
    目录概述结构总结在本讲,我们来学习一下行为型模式里面的第四个设计模式,即责任链模式。 概述 在学习责任链模式之前,我们先来看一下下面这段描述。 在现实生活中,常常会出现这样的事例:一...
    99+
    2024-04-02
  • 每天一个设计模式之责任链模式
    作者按:《每天一个设计模式》旨在初步领会设计模式的精髓,目前采用javascript和python两种语言实现。诚然,每种设计模式都有多种实现方式,但此小册只记录最直截了当的实现方式 :) 0. 项目地址 责任链模式·代码 《每天一个设...
    99+
    2023-01-31
    模式 责任
  • 设计模式之如何掌握责任链
    本篇内容主要讲解“设计模式之如何掌握责任链”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“设计模式之如何掌握责任链”吧!例子假设你也"穿越"到...
    99+
    2024-04-02
  • Java设计模式之责任链模式的示例详解
    目录应用场景实际代码案例无模式情况下的代码采用责任链模式优化代码采用建造者+责任链模式优化代码责任链模式优缺点责任链模式是将链中的每一个节点看做是一个对象,每个节点处理的请求均不相同...
    99+
    2022-11-13
    Java 设计模式 责任链模式 Java 责任链模式
  • JavaScript设计模式之责任链模式的的示例分析
    这篇文章主要介绍了JavaScript设计模式之责任链模式的的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。本文实例讲述了JavaS...
    99+
    2024-04-02
  • PHP如何实现职责链设计模式
    这篇文章主要介绍“PHP如何实现职责链设计模式”,在日常操作中,相信很多人在PHP如何实现职责链设计模式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP如何实现职责链设计模式”的疑惑有所帮助!接下来,请跟...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作