责任链模式--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 }

 

转载于:https://www.cnblogs.com/littleQin/p/3685424.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值