• Java设计模式8,校验、审批流程改善神器,责任链模式


    目录

    一、责任链模式

    最近在做一个数据校验的功能,需要校验的东西很多,有的从数据库中查询,有的是固定的数值校验,有的是数据类型校验, 如果通过ifelse来写,也是没问题的。

    但,为了代码的优雅和可扩展性,我选择尝试一下责任链模式,责任链模式的核心是 解决一组服务中的先后执行处理关系 。

    责任链模式(Chain of Responsibility Pattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。属于行为型模式。

    二、责任链模式的优缺点

    1. 减少大量ifelse;

    2. 逻辑清晰明了,添加删除节点、改变节点顺序方便快捷;

    3. 请求与处理解耦;

    4. 请求处理者只需关注自己感兴趣的请求,对于不感兴趣的请求,直接转发给下一级节点对象;

    5. 易于扩展新的请求处理类,符合开闭原则

    6. 责任链太长或处理时间过长,会影响整体性能。

    7. 如果需要判断的东西较多,容易造成类保证;

    8. 如果每个判断逻辑较简单,可能会造成一个类只做一个小小的数值判断,哈哈;

    9. 如果节点对象存在循环链接,可能会造成死循环;

    三、违背原则方案

    对实体类程序员Programmer的数据进行校验,校验名字、项目、项目完成时间。

    力求通过最简单的代码,通俗易懂的讲解责任链模式。

    1、Programmer实体类

    1. <pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.guor.bean;
    2. import lombok.Data;
    3. import java.util.Date;
    4. @Data
    5. public class Programmer {
    6. // 姓名
    7. private String name;
    8. // 项目
    9. private String project;
    10. // 模块
    11. private String module;
    12. // 进度
    13. private double schedule;
    14. // 计划完成时间
    15. private Date completePlanTime;
    16. // 详细信息
    17. private String info;
    18. }

    2、数据校验

    1. class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.guor.chain;
    2. import com.guor.bean.Programmer;
    3. public class Check {
    4. public boolean programmerCheck(Programmer programmer){
    5. if(!"公众号".equals(programmer.getProject())){
    6. return false;
    7. }
    8. if(!"哪吒编程".equals(programmer.getName())){
    9. return false;
    10. }
    11. if(!programmer.getInfo().equals("公众号哪吒编程,定期分享Java干货,还有不定期的送书活动,包邮到你家,哈哈")){
    12. return false;
    13. }
    14. return true;
    15. }
    16. }

    一堆ifelse安排上,代码还是比较清晰易懂的,再有新的判断,就继续添加ifelse就完了。

    3、但是,似乎违反了一些设计原则

    • 单一职责原则:指一个类或者模块应该有且只有一个改变的原因。
    • 开闭原则:软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的。
    • 接口隔离原则:尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。

    四、通过责任链模式重构代码

    1、链路抽象类定义

    这部分是责任链模式的核心代码,重点在于通过next获取下一个节点。

    定义一个抽象方法doHandler供子类去实现,实现不同的业务逻辑。

    1. class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.guor.chain;
    2. import com.guor.bean.Programmer;
    3. public abstract class Handler<T> {
    4. protected Handler next;
    5. private void next(Handler next) {
    6. this.next = next;
    7. }
    8. public abstract boolean doHandler(Programmer programmer);
    9. public static class Builder<T> {
    10. private Handler head;
    11. private Handler tail;
    12. public Builder addHandler(Handler handler) {
    13. if (this.head == null) {
    14. this.head = this.tail = handler;
    15. return this;
    16. }
    17. this.tail.next(handler);
    18. this.tail = handler;
    19. return this;
    20. }
    21. public Handler build() {
    22. return this.head;
    23. }
    24. }
    25. }

    2、校验项目名称

    1. class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.guor.chain;
    2. import com.guor.bean.Programmer;
    3. /**
    4. * 校验项目名称
    5. */
    6. public class ProjectHandler extends Handler {
    7. @Override
    8. public boolean doHandler(Programmer programmer) {
    9. if(!"公众号".equals(programmer.getProject())){
    10. return false;
    11. }
    12. if(null == next){
    13. return true;
    14. }
    15. return next.doHandler(programmer);
    16. }
    17. }

    3、校验名字

    1. class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.guor.chain;
    2. import com.guor.bean.Programmer;
    3. /**
    4. * 校验名字
    5. */
    6. public class NameHandler extends Handler {
    7. @Override
    8. public boolean doHandler(Programmer programmer) {
    9. if(!"哪吒编程".equals(programmer.getName())){
    10. return false;
    11. }
    12. if(null == next){
    13. return true;
    14. }
    15. return next.doHandler(programmer);
    16. }
    17. }

    4、校验活动细节

    1. class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.guor.chain;
    2. import com.guor.bean.Programmer;
    3. /**
    4. * 校验活动细节
    5. */
    6. public class InfoHandler extends Handler {
    7. @Override
    8. public boolean doHandler(Programmer programmer) {
    9. if(!programmer.getInfo().contains("扫描文末二维码,关注公众号哪吒编程,定期分享Java干货,还有不定期的送书活动,包邮到你家")){
    10. return false;
    11. }
    12. if(null == next){
    13. return true;
    14. }
    15. return next.doHandler(programmer);
    16. }
    17. }
    1. 先进行项目名称校验;
    2. 如果校验不通过,直接返回false;
    3. 如果校验通过,查看是否还有下一个校验节点;
    4. 如果没有,则直接返回;
    5. 如果有,则进行下一个节点的校验;以此类推!

    5、测试类

    责任链模式的设计,可以方便的进行扩展和维护,去掉了低俗的ifelse代码。

    实际项目中的数据校验要复杂的多,还有一些审批流程、付款流程,都可以通过责任链模式进行改造,非常好用!

    很多人觉得设计模式很简单,但是,能够熟练的将设计模式应用在自己的项目中,将各模块、功能规划的井井有条,运用的炉火纯青、恰到好处,真的很难。反复阅读,仔细体会。

     

  • 相关阅读:
    LeetCode-672. 灯泡开关 Ⅱ【穷举,位运算】
    实现微服务:匹配系统(中)
    这个Python代码为什么会出现报错呢?正确应该怎么写呢
    Qt QPixmap旋转图像
    MHA高可用配合及故障切换
    LayaBox---TypeScript---枚举
    FFmpeg开发笔记(三十四)Linux环境给FFmpeg集成libsrt和librist
    VSCODE+PHP8.2配置踩坑记录
    解决LiveData数据倒灌的新思路
    [BSidesCF 2020]Had a bad day1
  • 原文地址:https://blog.csdn.net/Java_ttcd/article/details/126403794