设计模式-责任链模式

责任链模式例子:中国古代女子有“三从四德”的道德规范,就是说一个女性,在没有结婚的时候听父亲的,结婚了之后听丈夫的,丈夫死了听儿子的。要是想出去逛街了,需要请示。作为父亲、丈夫、儿子只有两种选择:要不承担起责任来告诉她允许或不允许逛街,要不就让她请示下一个人。我们来看怎么把“三从”通过我们的程序来实现,需求很简单:通过程序描述一下古代妇女的“三从制度”,好,我们老看类图:
这里写图片描述
非常简单的类图,这个实现也非常简单,我们先看IWomen接口:

package com.nextvpu.myapplication;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 古代悲哀女性的总称
 */

public interface IWomen {

    //获得个人状况
    public int getType();

    //获得个人请示
    public String getRequest();

}

女性就两个参数,一个是当前的个人状况,是结婚了呢还是没结婚,丈夫有没有去世,另外一个要请示的内容,要出去逛街啊还是吃饭,我们来看类图:

package com.nextvpu.myapplication;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 古代女性的总称
 */

public class Women implements IWomen {

    /**
     * 通过一个int类型的参数来描述妇女的个人状况
     * 1--未出嫁
     * 2--出嫁
     * 3--夫死
     * @return
     */
    private int type = 0;

    //妇女的请示
    private  String request = "";

    @Override
    public int getType() {
        return this.type;
    }

    //构造函数传递过来请求
    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;
                break;
        }
    }


    @Override
    public String getRequest() {
        return this.request;
    }
}

我们使用数字来代表女性的不同状态,1 是为结婚 2 是已结婚,而且丈夫健在 3 丈夫去世了,儿子在
我们再来看有处理权的人员接口:

package com.nextvpu.myapplication;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 父系社会,那就是男性有至高权利,handler控制权
 */

public interface IHandler {

    //一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
    public void HandleMessage(IWomen women);

}

父亲、丈夫、儿子都是这个IHander接口的实现者:

package com.nextvpu.myapplication;

import android.util.Log;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 父亲
 */

public class Father implements IHandler {

    //未出嫁女儿来请示父亲
    @Override
    public void HandleMessage(IWomen women) {
        Log.e("xyz","女儿的请示是:"+women.getRequest());
        Log.e("xyz","父亲的答复是:,同意");
    }
}
package com.nextvpu.myapplication;

import android.util.Log;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 丈夫类
 */

public class Husband implements IHandler {

    //妻子请示丈夫
    @Override
    public void HandleMessage(IWomen women) {
        Log.e("xyz","妻子的请示是:"+women.getRequest());
        Log.e("xyz","丈夫的答复是:,同意");
    }
}
package com.nextvpu.myapplication;

import android.util.Log;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 儿子类
 */

public class Son implements IHandler {

    //目前向儿子请示
    @Override
    public void HandleMessage(IWomen women) {
        Log.e("xyz","母亲的请示是:"+women.getRequest());
        Log.e("xyz","儿子的答复是:,同意");
    }
}

这三个类非常非常简单,就一个方法,处理女儿、妻子、母亲提出的请求,再来看Client是怎么组装的:

    private void Client() {
        //随机挑选几个女性
        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){//未婚少女,请示父亲
                Log.e("xyz","\n--------女儿向父亲请示----");
                father.HandleMessage(women);
            }else if (women.getType()==2){
                Log.e("xyz","\n--------妻子向丈夫请示----");
                husband.HandleMessage(women);
            }else if (women.getType()==3){
                Log.e("xyz","\n--------母亲向儿子请示----");
                son.HandleMessage(women);
            }else{
                //暂时啥都不做
            }
        }
    }

“三从四德”的旧社会规范已经完整的表现出来了,但是有问题:
失去面对对象的意义。对女儿提出的请示,应该在父亲类中做出决定,父亲这个类应该是知道女儿的请求应该自己处理,而不是在Client类中进行组装出来,也就是说原本应该是父亲这个类做的事情抛给了其他类进行处理;
迪米特法则相违背。我们在Client类中写了if…selse的判断条件,你看这个条件内都有一个接口IHandler的三个实现类,谁能处理那个请求,怎么处理,直接在实现类中定义好不就结了吗?你的类我知道的越少越好,别让我猜测你类中的逻辑,想想看,把这段if…else移动到三个实现类中该怎么做?
耦合过度。我们要根据Women的type来决定使用IHandler的那个实现类来处理请求,我问你,如果IHandler的实现类继续扩展在呢么办?修改Client类?与开闭原则违背咯。
异常情况没有考虑。妻子只向丈夫请示吗?如果妻子向自己丈夫请示了,父亲应该做何处理呢?我们的程序上可没有体现出来。
既然有那么多的问题,那我们要想办法来解决这些问题,我们可以抽象成这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就回应处理,如果女儿已经出嫁了,那就把请求转发到女婿这里来处理,那女婿要是不在了,那就由儿子来处理这个请求,类似于这样请求:
这里写图片描述
父亲、丈夫、儿子每个节点有两个选择:要么承担责任,做出回复;要么把请求转发到后序环节。结构分析已经很清楚了,那我们看怎么来实现这个功能,先看类图:
这里写图片描述
从类图上看,三个实现类Father、Husband、Son只要实现构造函数和父类中抽象方法就可以了,具体怎么处理这些请求,都已经转移到Handler抽象类中,我们来看handler怎么实现:

package com.nextvpu.myapplication;

import android.util.Log;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 父系社会,那就是男性有至高权利,handler控制权
 */

public abstract class Handler {
    //能处理的级别
    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 {//已经没有后续处理人了,不用处理
                Log.e("xyz","没地方请示了,不做处理!-----\n");

            }
        }
    }

    /**
     * 如果你属于你处理的返回,你应该让她找下一个环节的人,比如
     * 女儿出嫁了,还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
     * @param
     */
    public void setNext(Handler _handler){
        this.nextHandler = _handler;
    }

    //有请示那当然要回应
    public abstract void response(IWomen women);
}

有没有看到,其实这里也用到模版方法模式,在模版方法中判断请求的级别和当前能够处理的级别,如果相同则调用基本方法,作出反馈了如果不想等,则传递到下一个环节,有下一个环节做出回应,基本方法response要哥哥实现类都要实现,我们来看三个实现类:

package com.nextvpu.myapplication;

import android.util.Log;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 父亲
 */

public class FatherChange extends Handler {

    //父亲只处理女儿的请求
    public FatherChange(){
        super(1);
    }

    @Override
    public void response(IWomen women) {
        Log.e("xyz"," ---- 女儿想父亲请示 ---- ");
        Log.e("xyz"," women.getRequest()  "+women.getRequest());
        Log.e("xyz"," 父亲的答复是:同意\n ");
    }
}
package com.nextvpu.myapplication;

import android.util.Log;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 父亲
 */

public class HusbandChange extends Handler {

    //父亲只处理女儿的请求
    public HusbandChange(){
        super(2);
    }

    @Override
    public void response(IWomen women) {
        Log.e("xyz"," ---- 妻子向丈夫请示 ---- ");
        Log.e("xyz"," women.getRequest()  "+women.getRequest());
        Log.e("xyz"," 丈夫的答复是:同意\n ");
    }
}
package com.nextvpu.myapplication;

import android.util.Log;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 父亲
 */

public class SonChange extends Handler {

    //父亲只处理女儿的请求
    public SonChange(){
        super(3);
    }

    @Override
    public void response(IWomen women) {
        Log.e("xyz"," ---- 妻子向儿子请示 ---- ");
        Log.e("xyz"," women.getRequest()  "+women.getRequest());
        Log.e("xyz"," 儿子的答复是:同意\n ");
    }
}

这三个类都很简单,都早方法那是你必须实现的,父类已经定义了,子类不实现编译不通过,通构造方法我们设置了哥哥类能处理的请求类型,Father只能处理请求类型为1(也就是女儿)的请求;Husband只能处理请求类型为2(也就是妻子)的请求;儿子只能处理请求类型为3(也就是目前)的请求。
Women类的接口没有任何变化,实现类稍微修改,看代码:

package com.nextvpu.myapplication;

/**
 * Created by NEXTVPU on 2018/6/16.
 * 古代女性的总称
 */

public class Women implements IWomen {

    /**
     * 通过一个int类型的参数来描述妇女的个人状况
     * 1--未出嫁
     * 2--出嫁
     * 3--夫死
     * @return
     */
    private int type = 0;

    //妇女的请示
    private  String request = "";

    @Override
    public int getType() {
        return this.type;
    }

    //构造函数传递过来请求
    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;
                break;
        }
    }


    @Override
    public String getRequest() {
        return this.request;
    }
}

就是为了展示结果清晰一些,Women类做了一点改变,我们看最终实现类怎么描述:

private void ClientChange() {
        //随机挑选几个女性
        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 FatherChange();
        Handler husband = new HusbandChange();
        Handler son = new SonChange();

        //设置请示顺序
        father.setNext(husband);
        husband.setNext(son);

        for (IWomen women:arrayList
                ) {
          father.HandleMessage(women);
        }
    }

结果也正确,业务调用类ClientChnage也不用去判断到底是需要谁去处理,而且Handler抽象类的子类可以继续增加下去,只是我们这个传递链增加而已,调用类可以不用了解变化过程,甚至是谁在处理这个请求都不用知道。
以上讲解的就是责任链模式,你看Father、Husband、Son这三个类的处理女性的请求时是不是在传递呢,每个环节只有两个选项要么承担责任做出回应,要么向下传递请求,最终会有环节做出回应通用类图如下:
这里写图片描述
在通用类图中Handler是一个接口或者抽象类,每个抽象类都有两个方法HandlerRequest是处理请求,setNext是设置当前环节怎么把不属于自己处理的请求扔给谁,对于这个类图我觉得需要改变,融合来模版方法模式,类图如下:
这里写图片描述
想一想单一职责法则和迪米特法则吧,通过融合模版方法模式,各个实现类只要关注的自己业务逻辑就成了,至于说什么事要自己处理,那就让父类去决定好了,也就是说父类实现了请求传递的功能,子类实现请求的处理,符合单一职责法则,各个类只做一个动作或逻辑,也就是只有一个原因引起类的改变,我建议大家在使用的时候用这种方法,好处非常明显的了,子类实现非常简单,责任链的建立也非常的灵活。
责任链有一个缺点是大家开发的时候要注意:调试不是很方便,特别是链条比较长,环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂。
还有一个问题需要和大家说明一下,观察者模式也可以实现请求的传递,比如一个事件发生了,通知了观察者,同事观察者有作为一个被观察者,通知了另外一个观察者,这也形成了一个事件广播链,这个我们今天讲的责任链是有区别的:
受众数量不同。观察者广播链可以1:N的方式广播,而责任链要求是1:1的传递,必然有一个且只有一个类完成请求的处理;
请求内容不同。观察者广播链中的信息可以在传播中改变,但是责任链中的请求是不可改变的
处理逻辑不同。观察者广播链主要用于出发联动动作,而责任链则是对一个类型的请求按照既定的规则进行处理。

责任链模式DEMO下载地址:
demo下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值