zoukankan      html  css  js  c++  java
  • 责任链模式--ResponseChain

      模拟场景:在一个正规的公司中都是存在着健全的请假或者提薪规则的,以请假为例。如果员工在节假日或者平常时需要请假的时候,如果是两天内的话找项目经理请假即可。而超过两天的经理无权受理。五天内的找总监,超过五天总监无权受理。八天内找总经理申请。。。

      现在我们将上述的情景生成对应的类文件。首先,肯定存在员工类(Worker)、经理类(Manager)、总监类(Director)、总经理类(GeneralManager)。很明显,这里存在三个管理者类,有着相同的特性,都是可以对员工的请求进行回应。那么这个时候就可以抽象出一个ManageHandler接口,定义一个方法来受理员工的请求。当然也可以是抽象类。还有,一家公司不可能只有一名员工,所以定义一个IWorker接口,所有的员工都有一样的动作,没有特权。那么除了以上的类,是否还应该存在一个请求类(Request)呢?因为请求并不仅仅是属于某个员工的,可能两三个员工有着相同的请求呢?

      现在开始构建类

    IWorker

     1 package com.zqz.dp.responsechain1.worker;
     2 import com.zqz.dp.responsechain1.manage.ManageHandler;
     3 import com.zqz.dp.responsechain1.request.Request;
     4 /**
     5  * @author Qin
     6  * 员工的接口,所有的员工都有同一的属性
     7  */
     8 public interface IWorker {
     9     public String getName();    //取得员工的名字
    10     public void setRequest(Request request); // 设置员工的请求
    11     public Request getRequest(); // 得到员工的请求
    12     public void sendRequest(ManageHandler manageHandler); // 向管理者发出请求
    13 }

    Worker

     1 package com.zqz.dp.responsechain1.worker;
     2 import com.zqz.dp.responsechain1.manage.ManageHandler;
     3 import com.zqz.dp.responsechain1.request.Request;
     4 /**
     5  * @author Qin 
     6  * 员工类,员工中存放名字(String:name),员工的请求(Request:request)
     7  */
     8 public class Worker implements IWorker {
     9     private String name; // 员工的名字
    10     private Request request = null; // 员工的请求
    11     public Worker(String name) { // 构造方法赋值
    12         this.name = name;
    13     }
    14     @Override
    15     public void setRequest(Request request) { // 设置员工的请求
    16         this.request = request;
    17     }
    18     @Override
    19     public Request getRequest() { // 取得员工的请求
    20         return request;
    21     }
    22     @Override
    23     public void sendRequest(ManageHandler manager) { // 向管理者发出请求
    24         manager.handlerMessage(this);
    25     }
    26     @Override
    27     public String getName() { // 取得员工姓名
    28         return this.name;
    29     }
    30 }

    Request

     1 package com.zqz.dp.responsechain1.request;
     2 /**
     3  * @author Qin 请求类,包含请求的类型和数量
     4  */
     5 public class Request {
     6     private String requestType; // 请求的类型
     7     private int requestNum; // 请求的数量
     8     public Request(String requestType, int requestNum) { // 构造方法赋值
     9         this.requestType = requestType;
    10         this.requestNum = requestNum;
    11     }
    12     /**
    13      * getter、setter方法
    14      */
    15     public String getRequestType() {
    16         return requestType;
    17     }
    18     public int getRequestNum() {
    19         return requestNum;
    20     }
    21 }

    ManageHandler

    1 package com.zqz.dp.responsechain1.manage;
    2 import com.zqz.dp.responsechain1.worker.IWorker;
    3 /**
    4  * @author Qin
    5  * 管理者类,所有的管理者要实现该接口
    6  */
    7 public interface ManageHandler {
    8     void handlerMessage(IWorker worker);        //做出相应的动作,指明是哪个员工发出的请求
    9 }

    Manager

     1 package com.zqz.dp.responsechain1.manage;
     2 import com.zqz.dp.responsechain1.worker.IWorker;
     3 /**
     4  * @author Qin 
     5  * 经理类,经理可以做出相应的响应,实现接口中的方法
     6  */
     7 public class Manager implements ManageHandler {
     8     private String name; // 经理的名字
     9     private IWorker worker; // 提交申请的员工
    10     public Manager(String name) { // 构造方法赋值
    11         this.name = name;
    12     }
    13     @Override
    14     public void handlerMessage(IWorker worker) { // 处理员工的请求
    15         this.worker = worker; // 指明员工对象
    16         String requestType = this.worker.getRequest().getRequestType(); // 得到员工的请求类型
    17         int requestNum = this.worker.getRequest().getRequestNum(); // 得到员工的请求数量
    18         if ("请假".equals(requestType) && requestNum <= 2) { // 表示请假两天内可以进行决策
    19             System.out.println(this.name + "说:同意〖" + worker.getName() + "〗"
    20                     + requestType + requestNum + "天"); // 做出决定
    21         } else {
    22             System.out.println(this.name + "说:我无权处理");// 做出决定
    23         }
    24     }
    25 }

    Director

     1 package com.zqz.dp.responsechain1.manage;
     2 import com.zqz.dp.responsechain1.worker.IWorker;
     3 /**
     4  * @author Qin
     5  * 总监类,总监可以做出相应的响应,实现接口中的方法
     6  */
     7 public class Director implements ManageHandler {
     8     private String name;    //总监的名字
     9     private IWorker worker;    //发送请求的员工    
    10     public Director(String name) {    //构造方法赋值
    11         this.name=name;
    12     }
    13     @Override
    14     public void handlerMessage(IWorker worker) {    //处理员工的请求
    15         this.worker=worker;        //赋值
    16         String requestType=this.worker.getRequest().getRequestType();    //得到员工请求的类型
    17         int requestNum=this.worker.getRequest().getRequestNum();    //得到员工请求的数量
    18         if("请假".equals(requestType)&&requestNum<=5){    // 表示请假五天内可以进行决策
    19             System.out.println(this.name+"说:同意〖"+worker.getName()+"〗"+requestType+requestNum+"天");
    20         }else{
    21             System.out.println(this.name+"说:我无权处理");
    22         }
    23     }
    24 }

    GeneralManager

     1 package com.zqz.dp.responsechain1.manage;
     2 import com.zqz.dp.responsechain1.worker.IWorker;
     3 /**
     4  * @author Qin
     5  * 总经理类,总经理可以做出相应的响应,实现接口中的方法
     6  */
     7 public class GeneralManager implements ManageHandler {
     8     private String name;    //总经理的名字
     9     private IWorker worker;    //请求的员工
    10     public GeneralManager(String name) {    //构造方法赋值
    11         this.name=name;
    12     }
    13     @Override
    14     public void handlerMessage(IWorker worker) {    //处理员工的请求
    15         this.worker=worker;        //赋值
    16         String requestType=this.worker.getRequest().getRequestType();    //得到请求的类型
    17         int requestNum=this.worker.getRequest().getRequestNum();        //得到请求的数量
    18         if("请假".equals(requestType)&&requestNum<=8){    //表示请假八天内可以受理
    19             System.out.println(this.name+"说:同意〖"+worker.getName()+"〗"+requestType+requestNum+"天");
    20         }else{
    21             System.out.println(this.name+"说:我无权处理");
    22         }
    23     }
    24 }

    Client

     1 package com.zqz.dp.responsechain1.client;
     2 import com.zqz.dp.responsechain1.manage.Director;
     3 import com.zqz.dp.responsechain1.manage.GeneralManager;
     4 import com.zqz.dp.responsechain1.manage.Manager;
     5 import com.zqz.dp.responsechain1.request.Request;
     6 import com.zqz.dp.responsechain1.worker.Worker;
     7 /**
     8  * @author Qin
     9  * 客户端,员工发出请求,管理者进行回应
    10  */
    11 public class Client {
    12     /**
    13      * @param args
    14      */
    15     public static void main(String[] args) {
    16         Worker worker=new Worker("张三");        //得到员工对象
    17         Request request=new Request("请假",3);    //得到请求对象
    18         worker.setRequest(request);            //把请求设置到员工对象中,表示员工有该请求
    19         Manager manager=new Manager("经理");        //经理类
    20         Director director=new Director("总监");    //总监类
    21         GeneralManager generalManager=new GeneralManager("总经理");//总经理类
    22         worker.sendRequest(manager);    //员工向经理发送请求
    23         worker.sendRequest(director);//员工向总监发送请求
    24         worker.sendRequest(generalManager);//员工向总经理发送请求
    25     }
    26 }

      按上面的操作确实可以完成了操作,但是上面的代码是不合适的。因为该员工同时向三位领导发出了请求。或许有读者会反馈说可以先进行判断,如果再决定向那个领导发出请求。其实这也是不合适的,这样员工和领导的耦合度太强了。一般请假的时候,最好只向一个领导发出请求,该领导无法受理的时候就交给其他领导。记住,是领导交给其他领导,而不是你交给其他领导。这样就降低了耦合度。想想,如果是员工自己请求其他领导,那高级领导是否会接触一大堆底层员工呢?很明显这样不合适,而且有低级领导向高级领导提出申请,或许帮你美言几句机会更大了。

      以上说的就是责任链模式,底层对象只和另一个对象进行交互,具体是哪个对象来处理该请求,底层对象不关心。在这里,是哪个领导批准的员工不关心,员工关心的是请求能否通过。

      细心的读者会发现,上面的操作中,Manager、Director、GeneralManager类中共同的代码太多了,这个时候会发现把接口修改成类来继承的话会减少好多重复代码。细心观察,在HandlerMessage中,不同的只是管理者允许请假的天数不同,还有各个管理者的反馈信息不同而已。具体的天数可以通过否则方法进行赋值,也就是说在实例化管理者的时候,就给定该管理员有多少天的决定权。其实这个时候就可以使用模板设计模式了,把HandlerMessage方法定义为final,防止子类进行覆写,然后定义一个抽象的response方法,表示每个管理者的反馈消息。

      为了达到解耦和的操作,在ManageHandler类中,采用链表的方式,定义一个ManageHandler类型的nextManager对象,表示的是管理者的直属领导,当管理者无权受理的时候就交给直属领导操作。

      修改部分模块的代码,如下

    ManageHandler

     1 package com.zqz.dp.responsechain2.manage;
     2 import com.zqz.dp.responsechain2.worker.IWorker;
     3 /**
     4  * @author Qin
     5  * 管理者类,所有的管理者要实现该接口
     6  */
     7 public abstract class ManageHandler {
     8     private IWorker worker;        //发出请求的员工
     9     private String name;        //管理者的名字
    10     private int num;            //管理者最多可以处理的数量(请假天数)
    11     private ManageHandler nextManager;    //设置管理者的直属领导
    12     public String getName() {        //得到领导的名字
    13         return name;    
    14     }
    15     public void setNextManager(ManageHandler nextManager) {
    16         this.nextManager = nextManager;
    17     }
    18     public ManageHandler(String name, int num) {    //构造方法赋值
    19         this.name = name;
    20         this.num = num;
    21     }
    22     public abstract void response(IWorker worker);    //领导作出反馈
    23     public final void handlerMessage(IWorker worker){        //做出相应的动作,指明是哪个员工发出的请求,final关键字表示不能进行覆写
    24         this.worker = worker; // 指明员工对象
    25         String requestType = this.worker.getRequest().getRequestType(); // 得到员工的请求类型
    26         int requestNum = this.worker.getRequest().getRequestNum(); // 得到员工的请求数量
    27         if ("请假".equals(requestType) && requestNum <= this.num) { // 表示请假两天内可以进行决策
    28             this.response(worker);// 做出决定
    29         } else {
    30             if(this.nextManager!=null){         //有直属领导
    31                 System.out.println(this.name+"说:我无权受理,要请示"+this.nextManager.getName());
    32                 this.nextManager.handlerMessage(worker);    //交给领导去操作
    33             }else{
    34                 System.out.println(this.name+"没回复,无法不通过...");
    35             }
    36         }
    37     }
    38 }

    Manager

     1 package com.zqz.dp.responsechain2.manage;
     2 import com.zqz.dp.responsechain2.worker.IWorker;
     3 /**
     4  * @author Qin 
     5  * 经理类,经理可以做出相应的响应,实现接口中的方法
     6  */
     7 public class Manager extends ManageHandler {
     8     public Manager(String name,int num) { // 构造方法赋值
     9         super(name,num);
    10     }
    11     @Override
    12     public void response(IWorker worker) {        //经理反馈
    13         System.out.println(this.getName()+"说:鉴于〖"+worker.getName()+"〗工作认真,所以批准...");
    14     }
    15 }

    Director

     1 package com.zqz.dp.responsechain2.manage;
     2 import com.zqz.dp.responsechain2.worker.IWorker;
     3 /**
     4  * @author Qin
     5  * 总监类,总监可以做出相应的响应,实现接口中的方法
     6  */
     7 public class Director extends ManageHandler {
     8     public Director(String name,int num) { // 构造方法赋值
     9         super(name,num);
    10     }
    11     @Override
    12     public void response(IWorker worker) {    //总监反馈
    13         System.out.println(this.getName()+"说:〖"+worker.getName()+"〗表现还行,通过...");
    14     }
    15 }

    GeranalManager

     1 package com.zqz.dp.responsechain2.manage;
     2 import com.zqz.dp.responsechain2.worker.IWorker;
     3 /**
     4  * @author Qin
     5  * 总经理类,总经理可以做出相应的响应,实现接口中的方法
     6  */
     7 public class GeneralManager extends ManageHandler {
     8     public GeneralManager(String name,int num) { // 构造方法赋值
     9         super(name,num);
    10     }
    11     @Override
    12     public void response(IWorker worker) {    //总经理反馈
    13         System.out.println(this.getName()+"说:时间太长了,不能通过...");
    14     }
    15 }

    Client

     1 package com.zqz.dp.responsechain2.client;
     2 import com.zqz.dp.responsechain2.manage.Director;
     3 import com.zqz.dp.responsechain2.manage.GeneralManager;
     4 import com.zqz.dp.responsechain2.manage.Manager;
     5 import com.zqz.dp.responsechain2.request.Request;
     6 import com.zqz.dp.responsechain2.worker.Worker;
     7 /**
     8  * @author Qin
     9  * 客户端,员工发出请求,管理者进行回应
    10  */
    11 public class Client {
    12     /**
    13      * @param args
    14      */
    15     public static void main(String[] args) {
    16         Worker worker=new Worker("张三");        //得到员工对象
    17         Request request=new Request("请假",8);    //得到请求对象
    18         worker.setRequest(request);            //把请求设置到员工对象中,表示员工有该请求
    19         Manager manager=new Manager("经理",2);        //经理类
    20         Director director=new Director("总监",5);    //总监类
    21         GeneralManager generalManager=new GeneralManager("总经理",8);//总经理类
    22         manager.setNextManager(director);        //设置经理的直属领导
    23         director.setNextManager(generalManager);    //设置总监的直属领导
    24         worker.sendRequest(manager);    //员工向经理发送请求
    25     }
    26 }

      上面就完成了责任链模式,而且还结合了模板设计模式。会发现,Client端的代码并没有修改很多,但是员工只是向经理发出了请求,并未向其他领导提出,却得到了其他领导的反馈消息,真正做到了解耦合。

      责任链模式的定义:使多个对象都有机会去处理用户发出来的请求,从而避免了请求的发送者和接收和的耦合。将多个对象连成一条链,并沿着这条链传递该请求,最后得到接口。其实责任链模式跟链表的知识是一样的。

      责任链模式中,要注意一下几点:一是定义一个对外开放的处理请求方法,如HandlerMessage。二是定义一个链的编排方法,如setNextManager。三是具体的处理类要定义自己的处理方法,和自己处理的等级。如response方法,构造方法传递num。

    责任链模式的优点:

      将请求和处理分开来,请求不需要知道谁处理了该请求。

    责任链模式的缺点:

      1、  性能不高,每次都要从链头开始查找,如果处理对象再链尾的话,性能较差。

      2、  当链表较长时,调试不方便。注意:尽量避免长链的情况。

    责任链模式的拓展:

      学习jsp的同学应该对Filter不陌生吧,当有多个过滤器的时候,就是形成了一条过滤器链。不同的是,过滤器会先把传递进来的数据进行拦截,进行一系列的操作,再交给下一个过滤器。当与数据库进行交互之后,返回的数据会先结果最后一个过滤器,逆着被过滤直到调用第一个过滤器。

      比如,现在有一个字符串:”request msg…”。有两个过滤器,在接收的过程中被修改为” request msg...first filter...second filter...”。经数据库操作(只是模拟)后response的值为“response msg…”反馈回来的时候得到的” response msg。。。Second Filter。。。First Filter。。。”。

      在转换为类文件中,最重要的是过滤器链的设置。过滤器链其实也是执行过滤的操作,不同的是过滤器链存放了好多个过滤器。过滤的时候取出每一个进行过滤。而调用每一个过滤器的时候,除了添加该过滤器链进行操作,其他的实际上还是调用过滤器链,循环取出其他过滤器。所以要把过滤器链传递到多个过滤器中。

      因此定义一个过滤器接口,有一个方法,方法中存放了过滤器链。所有的过滤器,包括过滤器链都要实现该接口。

    Filter

     1 package com.zqz.dp.webfilterchain.filter;
     2 import com.zqz.dp.webfilterchain.request.Request;
     3 import com.zqz.dp.webfilterchain.response.Response;
     4 /**
     5  * @author Qin
     6  * 定义一个过滤链的接口,所有的过滤操作都有同样的特性
     7  */
     8 public interface Filter {
     9     void doFilter(Request request,Response response,FilterChain chain);        //传递过滤器链实例,每次过滤最终都是调用过滤器链进行过滤的操作
    10 }

    FilterChain

     1 package com.zqz.dp.webfilterchain.filter;
     2 import java.util.ArrayList;
     3 import java.util.List;
     4 import com.zqz.dp.webfilterchain.request.Request;
     5 import com.zqz.dp.webfilterchain.response.Response;
     6 /**
     7  * @author Qin
     8  * 过滤链,用list来接收过滤链,把所有需要的过滤添加到list中,进行操作的时候取出list的过滤器进行过滤
     9  */
    10 public class FilterChain implements Filter{
    11     private int index=0;    //定义一个脚标,表示是否已达到list容器的大小
    12     private List<Filter> filters=new ArrayList<Filter>();    //实例化一个list,来装载过滤器
    13     public void addFilter(Filter filter){    //添加过滤器到list中
    14         this.filters.add(filter);    //添加到容器中
    15     }
    16     @Override
    17     public void doFilter(Request request, Response response,FilterChain chain) {    //过滤的操作
    18         if(index!=this.filters.size()){    //容器中的过滤器还未完成取出
    19             Filter filter=this.filters.get(index);        //进行过滤的操作
    20             this.index++;
    21             if(this.index==this.filters.size()){    //如果过滤器已将请求过滤完毕
    22                 response.getResponseMsg().append("response msg。。。");    //设置反馈的信息
    23             }
    24             filter.doFilter(request, response, chain);    //取出过滤器进行过滤的操作
    25         }
    26     }
    27 }

    FirstFilter

     1 package com.zqz.dp.webfilterchain.filter;
     2 import com.zqz.dp.webfilterchain.request.Request;
     3 import com.zqz.dp.webfilterchain.response.Response;
     4 /**
     5  * @author Qin
     6  * 第一个过滤器,表示进行过滤的操作
     7  */
     8 public class FirstFilter implements Filter {
     9     @Override
    10     public void doFilter(Request request, Response response,FilterChain chain) {
    11         request.getRequestMsg().append("first filter...");        //第一个过滤器接收的时候修改数据
    12         chain.doFilter(request, response, chain);    //执行下一个过滤器
    13         response.getResponseMsg().append("First Filter。。。");    //第一个过滤器接收后反馈
    14     }
    15 }

    SecondFilter

     1 package com.zqz.dp.webfilterchain.filter;
     2 import com.zqz.dp.webfilterchain.request.Request;
     3 import com.zqz.dp.webfilterchain.response.Response;
     4 /**
     5  * @author Qin
     6  * 第二个过滤器,表示进行过滤的操作
     7  */
     8 public class SecondFilter implements Filter {
     9     @Override
    10     public void doFilter(Request request, Response response,FilterChain chain) {
    11         request.getRequestMsg().append("second filter...");        //第二个过滤器接收的时候修改数据
    12         chain.doFilter(request, response, chain);        //执行下一个过滤器
    13         response.getResponseMsg().append("Second Filter。。。");    //第二个过滤器反馈信息
    14     }
    15 }

    Request

     1 package com.zqz.dp.webfilterchain.request;
     2 /**
     3  * @author Qin 请求类,包含请求信息
     4  */
     5 public class Request {
     6     private StringBuffer requestMsg=new StringBuffer(); // 定义发送的请求信息,StringBuffer可以进行值的修改
     7     public Request() {   // 为了方便,构造方法初始化的时候进行赋值。
     8         this.requestMsg.append("request msg...");
     9     }
    10     public StringBuffer getRequestMsg() {    //得到StringBuffer对象
    11         return requestMsg;
    12     }
    13     @Override
    14     public String toString() { // 重写toStirng方法
    15         return this.requestMsg.toString();
    16     }
    17 }

    Response

     1 package com.zqz.dp.webfilterchain.response;
     2 /**
     3  * @author Qin 信息经过滤器之后的反馈结果
     4  */
     5 public class Response {
     6     private StringBuffer responseMsg = new StringBuffer(); // 经过滤器过滤之后的返回结果
     7     public StringBuffer getResponseMsg() { // 得到StringBuffer对象
     8         return responseMsg;
     9     }
    10     @Override
    11     public String toString() { // 覆写toString
    12         return this.responseMsg.toString();
    13     }
    14 }

    Client

     1 package com.zqz.dp.webfilterchain.client;
     2 import com.zqz.dp.webfilterchain.filter.Filter;
     3 import com.zqz.dp.webfilterchain.filter.FilterChain;
     4 import com.zqz.dp.webfilterchain.filter.FirstFilter;
     5 import com.zqz.dp.webfilterchain.filter.SecondFilter;
     6 import com.zqz.dp.webfilterchain.request.Request;
     7 import com.zqz.dp.webfilterchain.response.Response;
     8 /**
     9  * @author Qin
    10  * 客户端,进行过滤的操作。
    11  */
    12 public class Client {
    13     /**
    14      * @param args
    15      */
    16     public static void main(String[] args) {
    17         Filter firstFilter=new FirstFilter();        //实例化第一个过滤器
    18         Filter secondFilter=new SecondFilter();        //实例化第二个过滤器
    19         FilterChain chain=new FilterChain();        //实例化过滤器链
    20         chain.addFilter(firstFilter);        //把第一个过滤器添加到过滤器链
    21         chain.addFilter(secondFilter);        //把第二个过滤器添加到过滤器链
    22         Request request=new Request();        //实例化一个request对象
    23         Response response=new Response();    //实例化一个response对象
    24         chain.doFilter(request,response, chain);    //开始执行过滤的操作
    25         System.out.println(request);    //输出
    26         System.out.println(response);    //输出
    27     }
    28 }
  • 相关阅读:
    linux 远程同步数据工具rsync (1)
    lamp+nginx代理+discuz+wordpress+phpmyadmin
    Linux nginx 配置 location 语法 正则表达式
    linux下用ctrl+r快速搜索history命令
    常用服务的默认端口
    nginx rewrite不支持if 嵌套也不支持逻辑或和逻辑并
    nginx的301与302如何配置
    nginx $document_uri 参数使用
    选项“6”对 /langversion 无效;必须是 ISO-1、ISO-2、3、4、5 或 Default
    为什么托管代码要慢
  • 原文地址:https://www.cnblogs.com/littleQin/p/3685424.html
Copyright © 2011-2022 走看看