设计模式之禅11

来源:互联网 发布:移动宽带 端口转发 编辑:程序博客网 时间:2024/06/05 08:14

设计模式之禅11

真刀实枪之责任链模式

  • “三从四德”--古代妇女的枷锁

    • 三从:未嫁从父、既嫁从夫、夫死从子
      • 也就是说,一位女性在结婚之前要听从父亲,在结婚之后要听从丈夫的,如果丈夫死了还要听从儿子的。
    • 看下类图
    • 代码

      • IWomen

        package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public interface IWomen {    // 获得个人的状况    public int getType();    // 获得个人请示    public String getRequest();}
      • Women

        package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Women implements IWomen {    // 妇女个人状况    private int type = 0;    // 妇女的请示    private String request = "";    public Women(int type, String request) {        super();        this.type = type;        this.request = request;    }    /*     * 1-未出嫁 2-出嫁 3-夫死     */    @Override    public int getType() {        return this.type;    }    @Override    public String getRequest() {        return this.request;    }}
      • IBandler

        package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public interface IHandler {    // 女性的要求,处理函数    public void HandleMessage(IWomen iwomen);}
      • Father

        package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Father implements IHandler {    @Override    public void HandleMessage(IWomen iwomen) {        // 女子的请示        System.out.println("女子向父亲请示:" + iwomen.getRequest());        // 父亲的答复是同意        System.out.println("父亲的答复是:同意!");    }}
      • Hasband

        package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Husband implements IHandler {    @Override    public void HandleMessage(IWomen iwomen) {        // 女子的请示        System.out.println("女子向丈夫请示:" + iwomen.getRequest());        // 父亲的答复是同意        System.out.println("丈夫的答复是:同意!");    }}
      • Son

        package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Son implements IHandler {    @Override    public void HandleMessage(IWomen iwomen) {        // 女子的请示        System.out.println("女子向儿子请示:" + iwomen.getRequest());        // 父亲的答复是同意        System.out.println("儿子的答复是:同意!");    }}
      • Client

        package com.peng.zrl;import java.util.ArrayList;import java.util.Random;import java.util.concurrent.Future;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Client {    public static void main(String[] args) {        // 随机挑选几个女性        Random random = new Random();        ArrayList<IWomen> lists = new ArrayList<IWomen>();        for (int i = 0; i < 10; i++) {            lists.add(new Women(random.nextInt(3) + 1, "我要去逛街!!"));        }        // 定义三个请示对象        Father man1 = new Father();        Husband man2 = new Husband();        Son man3 = new Son();        // 逛街请示        for (IWomen iWomen : lists) {            if (iWomen.getType() == 1) {// 向父亲请示                man1.HandleMessage(iWomen);            } else if (iWomen.getType() == 2) {// 向丈夫请示                man2.HandleMessage(iWomen);            } else if (iWomen.getType() == 3) {// 向儿子请示                man3.HandleMessage(iWomen);            }        }    }}
      • 执行结果(因为随机,执行结果不唯一)

        女子向儿子请示:我要去逛街!!儿子的答复是:同意!女子向丈夫请示:我要去逛街!!丈夫的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向儿子请示:我要去逛街!!儿子的答复是:同意!女子向丈夫请示:我要去逛街!!丈夫的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向丈夫请示:我要去逛街!!丈夫的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!
    • 有没有感觉有点别扭--虽然不迷信,但不符合正常的逻辑...还有以下几个问题:
      1. 职责界定不清晰:对女儿约束--应该在Father中来做,而不是在Client做;对妻子的约束--应该在Husband中来做,而不是在Client中做;对母亲的约束--应该在Son做,而不是在Client来做
      2. 代码臃肿:if-else太多
      3. 耦合过程:根据Women的type来决定使用IHandler的那个实现类来处理请求,这样导致IHandler做扩展的时候,就必须修改Client,违反了开闭原则
      4. 异常情况欠考虑:逻辑的错误--起死回生了
    • 有了问题那就解决吧--请示出去,答复是唯一的。过程如下

      • 女子的请求先发给父亲,如果女子结婚了就交给女子的丈夫处理;如果女子的丈夫去世,就交给其儿子处理,如下顺序处理图
      • 父亲、丈夫、儿子,每个节点有两个选择:要么承担责任,做出回应;要么把请求转发给后续环节。类图重写修正,如图:
      • 代码

        • IWomen

          package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public interface IWomen {    // 获得个人的状况    public int getType();    // 获得个人请示    public String getRequest();}
        • Women

          package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Women implements IWomen {    // 妇女个人状况    private int type = 0;    // 妇女的请示    private String request = "";    public Women(int type, String request) {        super();        this.type = type;        // 为了便于显示,这里做了处理        switch (this.type) {        case 1:            this.request = "女儿的请求:" + request;            break;        case 2:            this.request = "妻子的请求:" + request;            break;        case 3:            this.request = "母亲的请求:" + request;            break;        }    }    /*     * 1-未出嫁 2-出嫁 3-夫死     */    @Override    public int getType() {        return this.type;    }    @Override    public String getRequest() {        return this.request;    }}
        • Handler

          package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */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 iwomen) {        if (iwomen.getType() == this.level) {            this.response(iwomen);// 自己处理请求        } else {            if (this.nextHandler != null) {                // 交给下一个处理者                this.nextHandler.HandleMessage(iwomen);            } else {                // 没后续人处理了,不用处理了                System.out.println("~~~~~~。。没地方请示,你自己决定吧!");            }        }    }    public void setNextHandler(Handler handler) {        this.nextHandler = handler;    }    // 有请示,回应    protected abstract void response(IWomen iwomen);}
        • Father

          package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Father extends Handler {    public Father() {        super(Handler.FATHER_LEVEL_REQUEST);    }    @Override    protected void response(IWomen iwomen) {        System.out.println("女儿向父亲请示:");        System.out.println(iwomen.getRequest());        System.out.println("父亲的回答是:同意!");    }}
        • Husband

          package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Husband extends Handler {    public Husband() {        super(Handler.HUSBAND_LEVEL_REQUEST);    }    @Override    protected void response(IWomen iwomen) {        System.out.println("妻子向丈夫请示:");        System.out.println(iwomen.getRequest());        System.out.println("丈夫的回答是:同意!");    }}
        • Son

          package com.peng.zrl;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Son extends Handler {    public Son() {        super(Handler.SON_LEVEL_REQUEST);    }    @Override    protected void response(IWomen iwomen) {        System.out.println("母亲向儿子请示:");        System.out.println(iwomen.getRequest());        System.out.println("儿子的回答是:同意!");    }}
        • Client

          package com.peng.zrl;import java.util.ArrayList;import java.util.Random;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Client {    public static void main(String[] args) {        // 随机挑选几个女性        Random random = new Random();        ArrayList<IWomen> lists = new ArrayList<IWomen>();        for (int i = 0; i < 10; i++) {            lists.add(new Women(random.nextInt(4) + 1, "我要去逛街!!"));// 注意这里的随机数为[1,4]之间的整数,1,2,3可处理,4将自由处理        }        // 定义三个请示对象        Father man1 = new Father();        Husband man2 = new Husband();        Son man3 = new Son();        // 设置请示顺序        man1.setNextHandler(man2);        man2.setNextHandler(man3);        // 遍历        for (IWomen iWomen : lists) {            man1.HandleMessage(iWomen);            System.out.println("_____________________");            System.out.println("————————歇一会儿———————");            System.out.println("_____________________");        }    }}
        • 结果(由于随机数,结果不唯一)

          妻子向丈夫请示:妻子的请求:我要去逛街!!丈夫的回答是:同意!_____________________————————歇一会儿———————_____________________~~~~~~。。没地方请示,你自己决定吧!_____________________————————歇一会儿———————_____________________母亲向儿子请示:母亲的请求:我要去逛街!!儿子的回答是:同意!_____________________————————歇一会儿———————_____________________~~~~~~。。没地方请示,你自己决定吧!_____________________————————歇一会儿———————_____________________母亲向儿子请示:母亲的请求:我要去逛街!!儿子的回答是:同意!_____________________————————歇一会儿———————_____________________~~~~~~。。没地方请示,你自己决定吧!_____________________————————歇一会儿———————_____________________~~~~~~。。没地方请示,你自己决定吧!_____________________————————歇一会儿———————_____________________妻子向丈夫请示:妻子的请求:我要去逛街!!丈夫的回答是:同意!_____________________————————歇一会儿———————_____________________~~~~~~。。没地方请示,你自己决定吧!_____________________————————歇一会儿———————_____________________妻子向丈夫请示:妻子的请求:我要去逛街!!丈夫的回答是:同意!_____________________————————歇一会儿———————_____________________
        • 上述代码中,从父亲开始,匹配则进行处理,不匹配交给其丈夫;丈夫进行匹配,匹配则进行处理,不匹配交给其儿子;儿子进行匹配,匹配则进行处理,不匹配则自由处理;
        • 这里是确定有父亲,丈夫,儿子-----实际生活中,记得加判断是否已婚!!

责任链的定义

  • Avoid coupling the sender of a request to its receiver by gaving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.(使用多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,将这些对象连接成一条链,并沿着这条链一直传递该请求,直到有对象处理它为止)
  • 重点在链上,在链上传递请求,返回相应的结果
  • 类图
  • 解释
    1. Level--处理级别
    2. Request封装请求
    3. Response封装结果
  • 代码

    • Handler

      package zrl2;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public abstract class Handler {    private Handler nextHandler;    // 每个处理者必须对请求做出处理    public final Response handleMessage(Request request) {        Response response = null;        // 判断自己的处理级别        if (this.getHandlerLevel().equals(request.getRequestLevel())) {// 级别相同            response = this.echo(request);        } else {// 级别不同,进行传递                // 判断是否有下一个传递者            if (null != this.nextHandler) {// 有下一个对象                response = this.nextHandler.echo(request);            } else {// 没有下一个对象,结束传递                // 没有适当的处理者,自行处理            }        }        return response;    }    // 设置下一个处理者    public void setNextHandler(Handler handler) {        this.nextHandler = handler;    }    protected abstract Response echo(Request request);    // 处理级别    public abstract Level getHandlerLevel();}
    • ConcreteHandler1

      package zrl2;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class ConcreteHandler1 extends Handler {    //定义自己的处理逻辑    @Override    protected Response echo(Request request) {        return null;    }    //定义自己的 处理级别    @Override    public Level getHandlerLevel() {        return null;    }}
    • ConcreteHandler2

          package zrl2;    /**     * @author kungfu~peng     * @data 2017年11月21日     * @description     */    public class ConcreteHandler2 extends Handler {        //定义自己的处理逻辑        @Override        protected Response echo(Request request) {            return null;        }        //定义自己的 处理级别        @Override        public Level getHandlerLevel() {            return null;        }    }
    • ConcreteHandler3

      package zrl2;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class ConcreteHandler3 extends Handler {    //定义自己的处理逻辑    @Override    protected Response echo(Request request) {        return null;    }    //定义自己的 处理级别    @Override    public Level getHandlerLevel() {        return null;    }}
    • Level

      package zrl2;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Level {    // 请求级别}
    • Request

      package zrl2;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Request {    // 请求的等级    public Level getRequestLevel() {        return null;    }}
    • Response

      package zrl2;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Response {    // 处理者返回的数据}
    • Client

      package zrl2;/** * @author kungfu~peng * @data 2017年11月21日 * @description */public class Client {    public static void main(String[] args) {        // 声明所有的处理节点        Handler h1 = new ConcreteHandler1();        Handler h2 = new ConcreteHandler2();        Handler h3 = new ConcreteHandler3();        // 设置链的顺序        h1.setNextHandler(h2);        h2.setNextHandler(h3);        // 提交请求,返回结果        Response response = h1.handleMessage(new Request());    }}
    • 抽象处理者的三个职责
      1. 请求处理--handleMessage
      2. 链的编排方法--setNextHandler
      3. 具体的处理任务方法echo和处理级别getHandlerLevel
    • 补充:一般会有一个封装类将责任模式进行封装,也就是代替Client类,直接返回链中的第一个处理者,具体链的设置不需要高层确定关系,这样可以简化高层模块的调用,减少模块间的耦合,提高系统的灵活性

责任链模式的应用

  • 责任链优点
    1. 将请求和处理分开--两者解耦,提高系统的灵活性
  • 责任链缺点
    1. 性能问题:每个请求都是从链头到链尾
    2. 调试不方便:采用了类似递归的方式,调用的时候逻辑可能比较复杂
  • 注意事项
    1. 责任链中的节点数量需要控制,避免出现超长的链的情况,一般的做法是在Handler中设置在一个最大节点数量,在setNext方法中判断是否已经超过其阈值,超过则不允许该链的建立,避免无意识的破坏系统性能

最佳实践

  • 结合模板方法,各个实现类只关注自己的业务逻辑就行了---符合单一职责原则
  • 责任链模式屏蔽了请求的处理过程,只要把请求发送给第一个处理者,最终返回一个结果,不用关心到底是谁来处理的--责任链模式的核心
  • 责任链模式可以作为一种补救模式--一个请求一个处理者的项目要发展,处理者的数量增加,这时候在第一个后面增加处理者,形成处理链,即形如责任链模式
  • 例如登录界面的普通用户和vip用户的具体处理过程【统一入口,责任链中判断任务的具体处理】

声明

  • 摘自秦小波《设计模式之禅》第2版;
  • 仅供学习,严禁商业用途;
  • 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。