• 读书 | 设计模式之禅 - 责任链模式


    1. 实现古代妇女的“三从”制度

    一位女性在结婚之前要听从于父亲,结婚之后要听从于丈夫,如果丈夫死了还要听从于儿子。作为父亲、丈夫或儿子,只有两种选择:要不承担起责任来,允许她或不允许她逛街;要不就让她请示下一个人,这是整个社会体系的约束。

    下面来看如何通过程序来实现“三从”,需求很简单:通过程序描述一下古代妇女的“三从”制度。

    对应的类图:IHandler是三个有决策权对象的接口,IWomen是女性的代码

    在这里插入图片描述

    ① IWomen 接口

    public interface IWomen {
        /**
         * 获得个人状况
         *
         * @return 结婚了还是没结婚、丈夫是否在世
         */
        int getType();
    
        /**
         * 获得个人请示
         * @return 你要干什么?出去逛街?约会?还是看电影?
         */
        String getRequest();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    ② Women 实现类

    @NoArgsConstructor
    @AllArgsConstructor
    public class Women implements IWomen {
        /*
         * 通过一个int类型的参数来描述妇女的个人状况
         * 1--未出嫁
         * 2--出嫁
         * 3--夫死
         */
        private int type = 0;
    
        //妇女的请示
        private String request = "";
    
        @Override
        public int getType() {
            return type;
        }
    
        @Override
        public String getRequest() {
            return request;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    ③ IHandler 接口

    public interface IHandler {
        /**
         * 一个女性(女儿、妻子或者母亲)要求逛街,你要处理这个请求
         */
        public void HandleMessage(IWomen women);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ④ Father 实现类

    public class Father implements IHandler {
        /**
         * 未出嫁的女儿来请示父亲
         */
        public void HandleMessage(IWomen women) {
            System.out.println("女儿的请示是:" + women.getRequest());
            System.out.println("父亲的答复是:同意");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ⑤ Husband 实现类

    public class Husband implements IHandler {
        /**
         * 妻子向丈夫请示
         */
        public void HandleMessage(IWomen women) {
            System.out.println("妻子的请示是:" + women.getRequest());
            System.out.println("丈夫的答复是:同意");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ⑥ Son 实现类

    public class Son implements IHandler {
        /**
         * 母亲向儿子请示
         */
        public void HandleMessage(IWomen women) {
            System.out.println("母亲的请示是:" + women.getRequest());
            System.out.println("儿子的答复是:同意");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ⑦ Client 测试类

    public class Client {
        public static void main(String[] args) {
            //随机挑选几个女性
            Random rand = new Random();
            ArrayList<IWomen> arrayList = new ArrayList();
            for (int i = 0; i < 5; i++) {
                arrayList.add(new Women(rand.nextInt(4), "我要出去逛街"));
            }
            //定义三个请示对象
            IHandler father = new Father();
            IHandler husband = new Husband();
            IHandler son = new Son();
            for (IWomen women : arrayList) {
                if (women.getType() == 1) {
                    //未结婚少女,请示父亲
                    System.out.println("\n--------女儿向父亲请示-------");
                    father.HandleMessage(women);
                } else if (women.getType() == 2) {
                    //已婚少妇,请示丈夫
                    System.out.println("\n--------妻子向丈夫请示-------");
                    husband.HandleMessage(women);
                } else if (women.getType() == 3) {
                    //母亲请示儿子
                    System.out.println("\n--------母亲向儿子请示-------");
                    son.HandleMessage(women);
                } else {
                    //暂时什么也不做
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    上述代码实现存在职责界定不清晰,代码臃肿,耦合过重,异常情况欠考虑等问题。

    2. 实现古代妇女的“三从”制度-优化

    女性提出一个请示,必然要获得一个答复,甭管是同意还是不同意,总之是要一个答复的,而且这个答复是唯一的,不能说是父亲作出一个决断,而丈夫也作出了一个决断,也即是请示传递出去,必然有一个唯一的处理人给出唯一的答复。

    我们可以抽象成这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就作出回应处理,如果女儿已经出嫁了,那就要把这个请求转发到女婿来处理,那女婿一旦去天国报道了,那就由儿子来处理这个请求。

    在这里插入图片描述

    父亲、丈夫、儿子每个节点有两个选择:要么承担责任,做出回应;要么把请求转发到后序环节。

    在这里插入图片描述

    三个实现类Father、Husband、Son只要实现构造函数和父类中的抽象方法response就可以了,具体由谁处理女性提出的请求,都已经转移到了Handler抽象类中。

    ① Handler 抽象类

    public abstract class Handler {
        //可以处理的请求的级别
        public final static int FATHER_LEVEL_REQUEST = 1;
        public final static int HUSBAND_LEVEL_REQUEST = 2;
        public final static int SON_LEVEL_REQUEST = 3;
        
        //能处理的级别
        private int level = 0;
        
        //责任传递,下一个人责任人是谁
        private Handler nextHandler;
    
        //每个类都要说明一下自己能处理哪些请求
        public Handler(int _level) {
            this.level = _level;
        }
    
        
        public final void HandleMessage(IWomen women) {
            if (women.getType() == this.level) {
                //一个女性要求逛街,你要处理这个请求
                this.response(women);
            } else {
                //有后续环节,才把请求往后递送
                if (this.nextHandler != null) { 
                    this.nextHandler.HandleMessage(women);
                } else {
                    //已经没有后续处理人了,不用处理了
                    System.out.println("---没地方请示了,按不同意处理---\n");
                }
            }
        }
    
        /*
         * 如果不属于你处理的请求,你应该让她找下一个环节的人,如女儿出嫁了,
         * 还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
         */
        public void setNext(Handler _handler) {
            this.nextHandler = _handler;
        }
    
        //有请示那当然要回应
        protected abstract void response(IWomen women);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    其实在这里也用到模板方法模式,在模板方法中判断请求的级别和当前能够处理的级别,如果相同则调用基本方法,做出反馈;如果不相等,则传递到下一个环节,由下一环节做出回应,如果已经达到环节结尾,则直接做不同意处理。基本方法response需要各个实现类实现,每个实现类只要实现两个职责:一是定义自己能够处理的等级级别;二是对请求做出回应。

    ② Father 子类

    public class Father extends Handler {
        //父亲只处理女儿的请求
        public Father() {
            super(Handler.FATHER_LEVEL_REQUEST);
        }
    
        //父亲的答复
        protected void response(IWomen women) {
            System.out.println("--------女儿向父亲请示-------");
            System.out.println(women.getRequest());
            System.out.println("父亲的答复是:同意\n");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ③ Husband 子类

    public class Husband extends Handler {
        //丈夫只处理妻子的请求
        public Husband() {
            super(Handler.HUSBAND_LEVEL_REQUEST);
        }
    
        //丈夫请示的答复
        protected void response(IWomen women) {
            System.out.println("--------妻子向丈夫请示-------");
            System.out.println(women.getRequest());
            System.out.println("丈夫的答复是:同意\n");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ④ Son 子类

    public class Son extends Handler {
        //儿子只处理母亲的请求
        public Son() {
            super(Handler.SON_LEVEL_REQUEST);
        }
    
        //儿子的答复
        protected void response(IWomen women) {
            System.out.println("--------母亲向儿子请示-------");
            System.out.println(women.getRequest());
            System.out.println("儿子的答复是:同意\n");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这三个类都很简单,构造方法是必须实现的,父类框定子类必须有一个显式构造函数,子类不实现编译不通过。通过构造方法我们设置了各个类能处理的请求类型,Father只能处理请求类型为1(也就是女儿)的请求;Husband只能处理请求类型类为2(也就是妻子)的请求,儿子只能处理请求类型为3(也就是母亲)的请求,那如果请求类型为4的该如何处理呢?在Handler中我们已经判断了,如何没有相应的处理者(也就是没有下一环节),则视为不同意。

    ⑤ Women 实现类

    public class Women implements IWomen {
        /*
         * 通过一个int类型的参数来描述妇女的个人状况
         * 1--未出嫁
         * 2--出嫁
         * 3--夫死
         */
        private int type = 0;
        
        //妇女的请示
        private String request = "";
    
        //构造函数传递过来请求
        public Women(int type , String request) {
            this.type = type;
            //为了便于显示,在这里做了点处理
            switch (this.type) {
                case 1:
                    this.request = "女儿的请求是:" + request;
                    break;
                case 2:
                    this.request = "妻子的请求是:" + request;
                    break;
                case 3:
                    this.request = "母亲的请求是:" + request;
                default:
                    
            }
        }
    
        //获得自己的状况
        public int getType() {
            return this.type;
        }
    
        //获得妇女的请求
        public String getRequest() {
            return this.request;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    ⑥ Client 测试类

    public class Client {
        public static void main(String[] args) {
            //随机挑选几个女性
            Random rand = new Random();
            ArrayList<IWomen> arrayList = new ArrayList();
            for (int i = 0; i < 5; i++) {
                arrayList.add(new Women(rand.nextInt(4), "我要出去逛街"));
            }
            //定义三个请示对象
            Handler father = new Father();
            Handler husband = new Husband();
            Handler son = new Son();
            //设置请示顺序
            father.setNext(husband);
            husband.setNext(son);
            for (IWomen women : arrayList) {
                father.HandleMessage(women);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在Client中设置请求的传递顺序,先向父亲请示,不是父亲应该解决的问题,则由父亲传递到丈夫类解决,若不是丈夫类解决的问题则传递到儿子类解决,最终的结果必然有一个返回。

    3. 责任链模式的定义

    使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

    责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果:

    在这里插入图片描述

    ① Handler 抽象类

    public abstract class Handler {
        
        private Handler nextHandler;
    
        //每个处理者都必须对请求做出处理
        //被final修改的抽象方法不能被继承
        public final Response handleMessage(Request request) {
            Response response = null;
            //判断是否是自己的处理级别
            if (this.getHandlerLevel().equals(request.getRequestLevel())) {
                response = this.echo(request);
            } else { 
                //不属于自己的处理级别
                //判断是否有下一个处理者
                if (this.nextHandler != null) {
                    response = this.nextHandler.handleMessage(request);
                } else {
                    //没有适当的处理者,业务自行处理
                }
            }
            return response;
        }
    
        //设置下一个处理者是谁
        public void setNext(Handler _handler) {
            this.nextHandler = _handler;
        }
    
        //每个处理者都有一个处理级别
        protected abstract Level getHandlerLevel();
    
        //每个处理者都必须实现处理任务
        protected abstract Response echo(Request request);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    ② ConcreteHandler1 处理者子类

    public class ConcreteHandler1 extends Handler {
        /**
         * 定义自己的处理逻辑
         */
        protected Response echo(Request request) {
            //完成处理逻辑
            return null;
        }
    
        /**
         * 设置自己的处理级别
         */
        protected Level getHandlerLevel() {
            //设置自己的处理级别
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ③ ConcreteHandler2 处理者子类

    public class ConcreteHandler2 extends Handler {
        /**
         * 定义自己的处理逻辑
         */
        protected Response echo(Request request) {
            //完成处理逻辑
            return null;
        }
    
        /**
         * 定义自己的处理逻辑
         */
        protected Level getHandlerLevel() {
            //设置自己的处理级别
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ④ ConcreteHandler3 处理者子类

    public class ConcreteHandler3 extends Handler {
        /**
         * 定义自己的处理逻辑
         */
        protected Response echo(Request request) {
            //完成处理逻辑
            return null;
        }
    
        /**
         * 设置自己的处理级别
         */
        protected Level getHandlerLevel() {
            //设置自己的处理级别
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ⑤ Client 测试类

    public class Client {
        public static void main(String[] args) {
            //声明所有的处理节点
            Handler handler1 = new ConcreteHandler1();
            Handler handler2 = new ConcreteHandler2();
            Handler handler3 = new ConcreteHandler3();
            //设置链中的阶段顺序1-->2-->3
            handler1.setNext(handler2);
            handler2.setNext(handler3);
            //提交请求,返回结果
            Response response = handler1.handlerMessage(new Request());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    责任链在实际的项目中使用也是比较多的,我曾经做过这样一个项目,界面上有一个用户注册功能,注册用户分两种,一种是VIP用户,也就是在该单位办理过业务的,一种是普通用户,一个用户的注册要填写一堆信息,VIP用户只比普通用户多了一个输入项:VIP序列号。注册后还需要激活,VIP和普通用户的激活流程也是不同的,VIP是自动发送邮件到用户的邮箱中就算激活了,普通用户要发送短信才能激活,为什么呢?获得手机号码以后好发广告短信啊!项目组就采用了责任链模式,甭管从前台传递过来的是VIP用户信息还是普通用户信息,统一传递到一个处理入口,通过责任链来完成任务的处理。

  • 相关阅读:
    docker概述
    【PWN】03.ret2syscall
    背会了常见的几个线程池用法,结果被问翻了
    RocketMQ(18)——高可用配置
    三、CPU基础-缓存
    基于SSM农产品商城系统
    Web前端学习笔记6(transform-style,flex)
    专访通过 OBCP V3 首位考生:V3 让知识更加结构化、体系化
    Python数据可视化和处理常用库(如Matplotlib、Seaborn)
    如何从外网远程控制企业内网电脑?
  • 原文地址:https://blog.csdn.net/qq_42764468/article/details/127595275