• Java设计模式----职责链模式


    假如有这样一个场景:小红做作业的时候,有一道题不会做,这时候,小红就去问同桌小明怎么做,小明表示也不会做,于是,小红又去问学习委员小黄,小黄也不会做,最后,小红不得不请教老师这个问题,老师给江红讲解了这个问题

    从上述场景中,我们看到小红依次找了 小明、小黄、老师,如果用流程图表示,那么就是:

     

    看起来就像是一条链条,一个请求,在链条上的各个节点间传递,知道请求被响应,这就是职责链模式


    1.职责链模式

    职责链模式(Chain of Responsibility): 将能够处理同一类请求的对象连成一条链,使这些对象都有机会处理请求,所提交的请求沿着链传递。从而避免请求的发送者和接受者之间的耦合关系。链上的对象逐个判断是否有能力处理该请求,如果能则就处理,如果不能,则传给链上的下一个对象。直到有一个对象处理它为止。       ----《大话设计模式》

    职责链模式的结构图图如下:

    这里的关键点,在于链上的节点Handler,持有一个指向下一节点的引用,实现的思想类似于数据结构中的链表。需要注意的是,对于一个请求,请求者和Handler都不知道该请求会在哪一个Handler被处理,每个Handler对象都要充分考虑清楚如何处理,防止请求走到最后一个Handler而无法被处理的情况发生。


    2.代码实现

    对于开篇的场景,我做了代码的演示。小红提出一个问题,封装为一个请求实体,我采用枚举类Request封装问题,按照难度等级分为不同请求对象:

    /**
     * 请求封装,使用枚举,分为:简单问题,普通问题,困难问题,超级难题
     */
    enum Request {
        SIMPLE_QUESTION,
        NORMAL_QUESTION,
        HARD_QUESTION,
        SUPER_HARD_QUESTION
    }

    然后是创建问题解答者的抽象类,RequestHandler,关键点是,此类聚合有本类实体other,代表着“下一个”节点,即问题的传播方向。定义了抽象方法answer,其子类需要override该方法以对请求进行处理。

    /**
     * 问题回答者的抽象类
     */
    abstract class RequestHandler {
        protected String name;
        public RequestHandler(String name) {
            this.name = name;
        }
    
        protected RequestHandler other;
        public void setHandler(RequestHandler handler) {
            other = handler;
        }
    
        public abstract void answer(Request question);
    }

    RequestHandler的三个子类:   分别代表同桌、学习委员、老师, 他们需要实现answer方法,对请求进行处理,注意要考虑周全请求无法处理的情况,也需要合理的结束请求在这条链上传播的过程。

    /**
     * 同桌
     */
    class Deskmate extends RequestHandler {
    
        public Deskmate(String name) {
            super(name);
        }
    
        @Override
        public void answer(Request question) {
            if (Request.SIMPLE_QUESTION == question) {
                System.out.printf("%s 解答了问题。
    ",name);
            }else{
                other.answer(question);
            }
        }
    }
    
    /**
     * 学习委员
     */
    class StudySecretary extends RequestHandler {
    
        public StudySecretary(String name) {
            super(name);
        }
    
        @Override
        public void answer(Request question) {
            if (Request.SIMPLE_QUESTION == question || Request.NORMAL_QUESTION == question) {
                System.out.printf("%s 解答了问题。
    ",name);
            } else{
                other.answer(question);
            }
        }
    }
    
    /**
     * 老师
     */
    class Teacher extends RequestHandler {
    
        public Teacher(String name) {
            super(name);
        }
    
        @Override
        public void answer(Request question) {
            if (Request.SIMPLE_QUESTION == question || Request.NORMAL_QUESTION == question ||
                    Request.HARD_QUESTION == question) {
                System.out.printf("%s 解答了问题。
    ",name);
            } else {
                System.out.println("问题太难,没人会。");
            }
        }
    }

    最后就是客户端调用,首先创建出三个Hanlder子类的实例, 然后给"同桌"和“学习委员”设置后继者,这样,就由“同桌”、“学习委员”、“老师”三个“节点”连成了一条链。“老师”没有设置后继者,为终点。

    问题的提问,我这里从“同桌”开始, 实际情况中,并不一定非得从“起点”开始, 并且节点之间的顺序,也可以改变。

    public class ChainDemo {
        public static void main(String[] args) {
            // 职责链上的"节点"
            RequestHandler deskmate = new Deskmate("同桌小明");
            RequestHandler studySecretaryre = new StudySecretary("学习委员小黄");
            RequestHandler teacher = new Teacher("老师");
    
            // 设置"后继者"
            deskmate.setHandler(studySecretaryre);
            studySecretaryre.setHandler(teacher);
    
            //从同桌开始提问
            deskmate.answer(Request.SIMPLE_QUESTION);
            deskmate.answer(Request.NORMAL_QUESTION);
            deskmate.answer(Request.HARD_QUESTION);
            deskmate.answer(Request.SUPER_HARD_QUESTION);
        }
    }

    输出结果

    同桌小明 解答了问题。
    学习委员小黄 解答了问题。
    老师 解答了问题。
    问题太难,没人会。

    3.总结

    通过一个场景:“教室里小红问同桌问题,同桌不会问学习委员,学习委员不会问老师”,这样一个生活例子,介绍了职责链模式。职责链模式的优点是降低了请求发送者和请求接收者的耦合度, 因为请求者只需要把问题发送给一个接收者就可以了,不需要关心具体是哪个接收者处理的问题结果。很明显,职责链模式,很适合在流程审批这类场景中应用,比如在公司发出一条请假审批, 不同职位对于员工请假天数的批准,有不同的权限,比如直接主管职能批准2天及以下,总监能批准5天......

    职责链模式扩展起来也比较方便,就像数据结构中链表的插入效率很高一个道理,职责链中在某两个节点之间插入一个新的节点,也只需要更改前一个节点的“后继者”而已。

    总之,应用任何实际模式,都要按需应用,不可滥用,比如如果流程成环了,就要注意职责链模式是否合适;或者是节点过多,那么以后万一请求变化了,每一个链上的节点都需要修改,这样就不大合适,这种场景,就应该考虑一个“中间人”的角色接收请求再转给其他实际接收者的模式了。

  • 相关阅读:
    备胎的养成记KeepAlived实现热备负载
    入坑系列之HAProxy负载均衡
    将Error异常日志从普通日志中剥离
    一步一步在Windows中使用MyCat负载均衡 下篇
    年终的第一篇总结 结束南漂 写在2017
    Android实现TCP断点上传,后台C#服务实现接收
    为什么我会反对大家写工作日报
    ANSI C、ISO C、Standard C联系与区别
    c、c++ char*和wchar*互相转换
    宽字符与Unicode (c语言 汉语字符串长度)
  • 原文地址:https://www.cnblogs.com/yxlaisj/p/10373059.html
Copyright © 2020-2023  润新知