模拟场景:在一个正规的公司中都是存在着健全的请假或者提薪规则的,以请假为例。如果员工在节假日或者平常时需要请假的时候,如果是两天内的话找项目经理请假即可。而超过两天的经理无权受理。五天内的找总监,超过五天总监无权受理。八天内找总经理申请。。。
现在我们将上述的情景生成对应的类文件。首先,肯定存在员工类(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 }