设计模式之禅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); } } }}
- 执行结果(因为随机,执行结果不唯一)
女子向儿子请示:我要去逛街!!儿子的答复是:同意!女子向丈夫请示:我要去逛街!!丈夫的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向儿子请示:我要去逛街!!儿子的答复是:同意!女子向丈夫请示:我要去逛街!!丈夫的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向丈夫请示:我要去逛街!!丈夫的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!女子向父亲请示:我要去逛街!!父亲的答复是:同意!
- 有没有感觉有点别扭--虽然不迷信,但不符合正常的逻辑...还有以下几个问题:
- 职责界定不清晰:对女儿约束--应该在Father中来做,而不是在Client做;对妻子的约束--应该在Husband中来做,而不是在Client中做;对母亲的约束--应该在Son做,而不是在Client来做
- 代码臃肿:if-else太多
- 耦合过程:根据Women的type来决定使用IHandler的那个实现类来处理请求,这样导致IHandler做扩展的时候,就必须修改Client,违反了开闭原则
- 异常情况欠考虑:逻辑的错误--起死回生了
有了问题那就解决吧--请示出去,答复是唯一的。过程如下
- 女子的请求先发给父亲,如果女子结婚了就交给女子的丈夫处理;如果女子的丈夫去世,就交给其儿子处理,如下顺序处理图
- 父亲、丈夫、儿子,每个节点有两个选择:要么承担责任,做出回应;要么把请求转发给后续环节。类图重写修正,如图:
代码
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.(使用多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,将这些对象连接成一条链,并沿着这条链一直传递该请求,直到有对象处理它为止)
- 重点在链上,在链上传递请求,返回相应的结果
- 类图
- 解释
- Level--处理级别
- Request封装请求
- 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()); }}
- 抽象处理者的三个职责
- 请求处理--handleMessage
- 链的编排方法--setNextHandler
- 具体的处理任务方法echo和处理级别getHandlerLevel
- 补充:一般会有一个封装类将责任模式进行封装,也就是代替Client类,直接返回链中的第一个处理者,具体链的设置不需要高层确定关系,这样可以简化高层模块的调用,减少模块间的耦合,提高系统的灵活性
责任链模式的应用
- 责任链优点
- 将请求和处理分开--两者解耦,提高系统的灵活性
- 责任链缺点
- 性能问题:每个请求都是从链头到链尾
- 调试不方便:采用了类似递归的方式,调用的时候逻辑可能比较复杂
- 注意事项
- 责任链中的节点数量需要控制,避免出现超长的链的情况,一般的做法是在Handler中设置在一个最大节点数量,在setNext方法中判断是否已经超过其阈值,超过则不允许该链的建立,避免无意识的破坏系统性能
最佳实践
- 结合模板方法,各个实现类只关注自己的业务逻辑就行了---符合单一职责原则
- 责任链模式屏蔽了请求的处理过程,只要把请求发送给第一个处理者,最终返回一个结果,不用关心到底是谁来处理的--责任链模式的核心
- 责任链模式可以作为一种补救模式--一个请求一个处理者的项目要发展,处理者的数量增加,这时候在第一个后面增加处理者,形成处理链,即形如责任链模式
- 例如登录界面的普通用户和vip用户的具体处理过程【统一入口,责任链中判断任务的具体处理】
声明
- 摘自秦小波《设计模式之禅》第2版;
- 仅供学习,严禁商业用途;
- 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。
阅读全文
0 0
- 设计模式之禅11
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- [设计模式]<<设计模式之禅>>模板方法模式
- 《设计模式之禅》目录
- 《设计模式之禅》前言
- 《设计模式之禅》书评
- 《设计模式之禅》书评
- 初读《设计模式之禅》
- 《设计模式之禅》书评
- 《设计模式之禅》摘记
- 设计模式之禅读书笔记
- 《设计模式之禅》读书笔记
- 在C# 中 textbox 文本的转换
- 栈的压入、弹出序列
- ndpi转换为wireshark的接口
- Ionic常用指令事件
- 神经网络能否代替决策树算法?
- 设计模式之禅11
- linux server运行图形化程序Xvfb
- 区域生长和matlab实现
- Ionic环境搭建
- c语言基础02
- hibernate框架的查询方式QBC(二十)
- 单例设计模式
- python numpy 按行归一化
- 86. Partition List