北风设计模式课程---责任链模式 总结

北风设计模式课程---责任链模式 总结

一、总结

一句话总结:

设置了级别的场景:责任链适合那些已经设置了级别的场景,
都有对应的抽象类:面向对象这些设计模式,处理类或者工厂类都有对应的抽象类,比如这里责任链模式的 处理类的抽象父类,作用自然是满足 开闭原则。

 

1、责任链模式 比正常例子可爱一点的 例子?

古代女子逛街请示:古代女子有“三从四德”之说,“三从”即指“未嫁从父、既嫁从夫、夫死从子”。举例来说,如果一位女性要出去逛街,在她出嫁前必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街。

古代女子有“三从四德”之说,“三从”即指“未嫁从父、既嫁从夫、夫死从子”。也就是说,一位女性在结婚之前要听从于父亲,结婚之后要听从于丈夫,如果丈夫死了还要听从于儿子。举例来说,如果一位女性要出去逛街,在她出嫁前必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街。估计你接下来马上要问:“要是没有儿子怎么办?”那就请示小叔子、侄子等。在父系社会中,妇女只占从属地位,现在想想中国古代的妇女还是挺悲惨的,连逛街都要多番请示。作为父亲、丈夫或儿子,只有两种选择:要不承担起责任来,允许她或不允许她逛街;要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则。

 

2、如下设计解决责任链模式的方法的缺点是什么?

|||-begin

class Client {
    public static void main(String[] args) {
        // 随机挑选几个女性
        Random rand = new Random();
        ArrayList<IWoman> arrayList = new ArrayList();
        for (int i = 0; i < 5; i++) {
            arrayList.add(new Woman(rand.nextInt(4), "我要出去逛街"));
        }
        // 定义三个请示对象
        IHandler father = new Father();
        IHandler husband = new Husband();
        IHandler son = new Son();
        for (IWoman woman : arrayList) {
            if (woman.getType() == 1) { // 未结婚少女, 请示父亲
                System.out.println("\n--------女儿向父亲请示-------");
                father.HandleMessage(woman);
            } else if (woman.getType() == 2) { // 已婚女子, 请示丈夫
                System.out.println("\n--------妻子向丈夫请示-------");
                husband.HandleMessage(woman);
            } else if (woman.getType() == 3) { // 母亲请示儿子
                System.out.println("\n--------母亲向儿子请示-------");
                son.HandleMessage(woman);
            } else {
                // 暂时什么也不做
            }
        }
    }
}

|||-end

职责界定不清晰:对女儿提出的请示,应该在父亲类中做出决定,因此 Father 类应该是知道女儿的请求自己处理,而不是在 Client 类中进行组装,不应该是这样的。
代码臃肿:我们在 Client 类中写了很多 if...else 的判断条件,而且能随着能处理该类型的请示人员越多,if...else 的判断就越多,代码就越来越臃肿,可读性就越来越低。
耦合严重:这是什么意思呢,我们要根据 Woman 的 type 来决定使用 IHandler 的那个实现类来处理请求。有一个问题是:如果 IHandler 的实现类继续扩展怎么办?修改 Client 类?这与开闭原则违背。
异常情况欠考虑:女子提出一个请示,必然要获得一个答复,甭管是同意还是不同意,总之是要一个答复的,而且这个答复是唯一的,不能说是父亲作出一个决断,而丈夫也作出了一个决断,正确的顺序应该是请求一层一层的传递的,父亲处理过后再由丈夫处理。

 

 

3、责任链抽象Handle类实例?

|||-begin

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(IWoman woman) {
        if (woman.getType() == this.level) {
            this.response(woman);
        } else {
            if (this.nextHandler != null) { // 有后续环节,
                this.nextHandler.HandleMessage(woman); // 才把请求往后递送this.nextHandler.HandleMessage(women);
            } else { // 已经没有后续处理人了, 不用处理了
                System.out.println("---没地方请示了, 按不同意处理---\n");
            }
        }
    }
 
    // 如果不属于你处理的请求, 你应该让她找下一个环节的人, 如女儿出嫁了, 还向父亲请示是否可以逛街, 那父亲就应该告诉女儿, 应该找丈夫请示
    public void setNext(Handler _nextHandler) {
        this.nextHandler = _nextHandler;
    }
 
    // 有请示那当然要回应
    protected abstract void response(IWoman woman);
}

|||-end

有级别 ,有处理请求,有找自己的下一级
找下一级的操作就是:设置(获取)下一级的对象:this.nextHandler = _nextHandler;

 

 

4、责任链 设计模式 优缺点?

优点:将请求者和处理者分开,两者解耦,提供系统灵活性。
缺点:请求都是从链头遍历到链尾,当链很长的时候,性能是个很大的问题。

 

 

 

二、责任链模式(十二)

转自或参考:责任链模式(十二)
https://blog.csdn.net/afei__/article/details/80677711

 

一、引子

古代女子有“三从四德”之说,“三从”即指“未嫁从父、既嫁从夫、夫死从子”。也就是说,一位女性在结婚之前要听从于父亲,结婚之后要听从于丈夫,如果丈夫死了还要听从于儿子。举例来说,如果一位女性要出去逛街,在她出嫁前必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街。估计你接下来马上要问:“要是没有儿子怎么办?”那就请示小叔子、侄子等。在父系社会中,妇女只占从属地位,现在想想中国古代的妇女还是挺悲惨的,连逛街都要多番请示。作为父亲、丈夫或儿子,只有两种选择:要不承担起责任来,允许她或不允许她逛街;要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则。

1. 针对这个例子,我们可以先定义一个女子的接口,如下:
public interface IWoman {
    int getType();
    // 获得个人请示, 你要干什么? 出去逛街? 约会?还是看电影?
    String getRequest();
}
2. 然后定义一个古代女子的类,实现这个接口
public class Woman implements IWoman {
 
    // 通过一个int类型的参数来描述妇女的个人状况 1--未出嫁 2--出嫁 3--夫死
    private int type = 0;
    // 女子的请示
    private String request = "";
 
    // 构造函数传递过来请求
    public Woman(int _type, String _request) {
        this.type = _type;
        this.request = _request;
    }
 
    // 获得自己的状况
    public int getType() {
        return this.type;
    }
 
    // 获得妇女的请求
    public String getRequest() {
        return this.request;
    }
}

 

二、错误示范

假如你之前并不知道责任链模式,你可能会如下设计:

1. 父亲、丈夫、儿子都是处理者,可以这么定义
public interface IHandler {
    // 你要处理这个请求
    void HandleMessage(IWoman woman);
}
 
public class Father implements IHandler {
    // 未出嫁的女儿请示父亲
    public void HandleMessage(IWoman woman) {
        System.out.println("父亲的答复是:同意");
    }
}
 
public class Husband implements IHandler {
    // 妻子请示丈夫
    public void HandleMessage(IWoman woman) {
        System.out.println("丈夫的答复是: 同意");
    }
}
 
public class Son implements IHandler {
    // 母亲请示儿子
    public void HandleMessage(IWoman woman) {
        System.out.println("儿子的答复是: 同意");
    }
}
2. 如上,还差一个场景类来模拟这个场景了
class Client {
    public static void main(String[] args) {
        // 随机挑选几个女性
        Random rand = new Random();
        ArrayList<IWoman> arrayList = new ArrayList();
        for (int i = 0; i < 5; i++) {
            arrayList.add(new Woman(rand.nextInt(4), "我要出去逛街"));
        }
        // 定义三个请示对象
        IHandler father = new Father();
        IHandler husband = new Husband();
        IHandler son = new Son();
        for (IWoman woman : arrayList) {
            if (woman.getType() == 1) { // 未结婚少女, 请示父亲
                System.out.println("\n--------女儿向父亲请示-------");
                father.HandleMessage(woman);
            } else if (woman.getType() == 2) { // 已婚女子, 请示丈夫
                System.out.println("\n--------妻子向丈夫请示-------");
                husband.HandleMessage(woman);
            } else if (woman.getType() == 3) { // 母亲请示儿子
                System.out.println("\n--------母亲向儿子请示-------");
                son.HandleMessage(woman);
            } else {
                // 暂时什么也不做
            }
        }
    }
}
3. 这样也可以正常运行,但是会存在以下几个问题:
  • 职责界定不清晰
    对女儿提出的请示,应该在父亲类中做出决定,因此 Father 类应该是知道女儿的请求自己处理,而不是在 Client 类中进行组装,不应该是这样的。
  • 代码臃肿
    我们在 Client 类中写了很多 if...else 的判断条件,而且能随着能处理该类型的请示人员越多,if...else 的判断就越多,代码就越来越臃肿,可读性就越来越低。
  • 耦合严重
    这是什么意思呢,我们要根据 Womantype 来决定使用 IHandler 的那个实现类来处理请求。有一个问题是:如果 IHandler 的实现类继续扩展怎么办?修改 Client 类?这与开闭原则违背。
  • 异常情况欠考虑
    女子提出一个请示,必然要获得一个答复,甭管是同意还是不同意,总之是要一个答复的,而且这个答复是唯一的,不能说是父亲作出一个决断,而丈夫也作出了一个决断,正确的顺序应该是请求一层一层的传递的,父亲处理过后再由丈夫处理。

 

 

三、正确示范

虽然你还不知道责任链模式是怎样定义的,但是哦我们可以先来看一下它可以怎样优雅地处理上面这种情况。

1. 首先重新定义一个抽象的 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(IWoman woman) {
        if (woman.getType() == this.level) {
            this.response(woman);
        } else {
            if (this.nextHandler != null) { // 有后续环节,
                this.nextHandler.HandleMessage(woman); // 才把请求往后递送this.nextHandler.HandleMessage(women);
            } else { // 已经没有后续处理人了, 不用处理了
                System.out.println("---没地方请示了, 按不同意处理---\n");
            }
        }
    }
 
    // 如果不属于你处理的请求, 你应该让她找下一个环节的人, 如女儿出嫁了, 还向父亲请示是否可以逛街, 那父亲就应该告诉女儿, 应该找丈夫请示
    public void setNext(Handler _nextHandler) {
        this.nextHandler = _nextHandler;
    }
 
    // 有请示那当然要回应
    protected abstract void response(IWoman woman);
}
2. 定义具体的实现类
public class Father extends Handler {
    // 父亲只处理女儿的请求
    public Father() {
        super(Handler.FATHER_LEVEL_REQUEST);
    }
 
    protected void response(IWoman woman) {
        System.out.println("父亲的答复是:同意\n");
    }
}
 
public class Husband extends Handler {
    // 丈夫只处理妻子的请求
    public Husband() {
        super(Handler.HUSBAND_LEVEL_REQUEST);
    }
 
    protected void response(IWoman woman) {
        System.out.println("丈夫的答复是: 同意\n");
    }
}
 
public class Son extends Handler {
    // 儿子只处理母亲的请求
    public Son() {
        super(Handler.SON_LEVEL_REQUEST);
    }
 
    protected void response(IWoman woman) {
        System.out.println("儿子的答复是: 同意\n");
    }
}
3. 模拟一个场景
class Client {
    public static void main(String[] args) {
        // 随机挑选几个女性
        Random rand = new Random();
        ArrayList<IWoman> arrayList = new ArrayList();
        for (int i = 0; i < 5; i++) {
            arrayList.add(new Woman(rand.nextInt(4), "我要出去逛街"));
        }
        // 定义三个请示对象
        Handler father = new Father();
        Handler husband = new Husband();
        Handler son = new Son();
        // 设置请示顺序
        father.setNext(husband);
        husband.setNext(son);
        for (IWoman woman : arrayList) {
            father.HandleMessage(woman);
        }
    }
}
4. 分析

结果也正确,业务调用类 Client 也不用去做判断到底是需要谁去处理,而且 Handler 抽象类的子类可以继续增加下去,只需要扩展传递链而已,调用类可以不用了解变化过程,甚至是谁在处理这个请求都不用知道。在这种模式下,该父亲处理就父亲处理,不该父亲处理就往下传递。 这就是责任链模式。

 

四、定义

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

 

五、类图及通用模版

一种通用模版的写法如下:

1. 抽象处理者
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 (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);
}

这里抽象的处理者实现三个职责:一是定义一个请求的处理方法 handleMessage,也是唯一对外开放的方法;二是定义一个链的编排方法 setNext,设置下一个处理者; 三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别 getHandlerLevel 和具体的处理任务 echo
注意这里 handleMessage 方法前面的 final 关键字,这里其实就是模版方法的一个使用,父类定义了部分方法的执行顺序,实际实现却是子类完成。

2. 其它相关接口类
public interface Request {
    // 获取请求的等级
    Level getRequestLevel();
}
 
 
public interface Response {
    // 返回的结果
}
 
 
public interface Level {
    // 等级的定义
}
3. 场景类
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);
        Request request = new ConcreteRequest();
        // 提交请求, 返回结果
        Response response = handler1.handleMessage(request);
    }
}

其实在实际应用中,一般还有有一个类来封装责任链,完成责任链的顺序编排,并返回链中的第一个处理者,这样上层逻辑就不再需要设置具体的责任链了,简化了上层逻辑,减少了模块间的耦合,系统也会更灵活。

 

六、优缺点

  • 优点
    将请求者和处理者分开,两者解耦,提供系统灵活性。
  • 缺点
    请求都是从链头遍历到链尾,当链很长的时候,性能是个很大的问题。
    一般我们可以在 Handler 中设置一个最大节点数量,在 setNext 方法中判断是否已经超过最大节点数,超过则不允许继续添加处理者,避免无意识的破坏系统性能。

 

 

 

转载于:https://www.cnblogs.com/Renyi-Fan/p/11073444.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值