问题:
在面向对象的设计中,经常会遇到有多个对象共同处理同一事件,但是各自对事件的处理权限却有不同的场合,一个比较简单的例子就是逐级审批,组长审批完成后,交给经理审批,经理审批完成交给总监,总监审批完给总裁...比较传统的解决办法就是,由客户端来判断,现在处于哪个阶段,下一步应调用哪个对象的方法,进入哪一个阶段,可是请求的发送者需要维护多个耦合,以处理请求信息的传达。这就存在请求的发送者与多个接收者之间是高耦合。
定义:
《设计模式》中给它的定义如下:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
意图:
Chain of Responsibility模式中ConcreteHandler将自己的后继对象(向下传递消息的对象)记录在自己的后继表中,通过这样的连接,将可能处理一个请求的对象链接成一个链,当一个请求到来时,ConcreteHandler会先检查看自己有没有匹配的处理程序,如果有就自己处理,否则传递给它的后继。这使得发出这个请求的客户端并不需要知道链上的哪一个对象最终处理这个请求,避免了请求的发出者与接收者之间的高耦合,客户端只需组织其责任链,并且设置请求,并可以动态地重新组织和分配责任。
参与者:
抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义出一个方法,以设定和返回对后继对象的引用。这个角色通常由一个抽象类或接口实现。
具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给后继对象。由于具体处理者持有对后继对象的引用,因此,如果需要,具体处理者可以访问后继对象。
UML:
纯与不纯:
责任链模式的纯与不纯的区别,就像黑猫、白猫的区别一样。不要刻意的去使自己的代码来符合一个模式的公式。只要能够使代码降低耦合、提高重用,满足系统需求并能很好的适应变化就好了。正所谓:管它黑猫白猫,抓住老鼠就是好猫!
纯的责任链模式,规定一个具体处理者角色只能对请求作出两种动作:自己处理;传给下家。不能出现处理了一部分,把剩下的传给了下家的情况。而且请求在责任链中必须被处理,而不能出现无果而终的结局。
反之,则就是不纯的责任链模式。
不纯的责任链模式还算是责任链模式吗?比如一个请求被捕获后,每个具体处理者都尝试去处理它,不管结果如何都将请求再次转发。我认为这种方式的实现,算不算是责任链模式的一种倒不重要,重要的是我们也能从中体味到责任链模式的思想:通过将多个处理者之间建立联系,来达到请求与具体的某个处理者的解耦。
实例:
1 public abstract class Handler {
2 protected Handler successor;
3 protected String name;
4
5 public String getName() {
6 return name;
7 }
8
9 //处理请求,由子类完成
10 public abstract void handleRequest(String request);
11
12 //设置下一个处理请求的人
13 public void setNextHandler(Handler successor) {
14 this.successor = successor;
15 }
16 }
17
18 public class LaoShi extends Handler{
19 public LaoShi(String name) {
20 this.name = name;
21 }
22
23 public void handleRequest(String request) {
24 if ("请假不去上课".equals(request)) {
25 System.out.println(name + "可以处理" + request + ",给予批准!");
26 } else {
27 System.out.println(name + "不可以处理" + request + "转交给"
28 + successor.getName());
29 successor.handleRequest(request);
30 }
31 }
32
33 }
34 public class BanZhang extends Handler {
35 public BanZhang(String name) {
36 this.name = name;
37 }
38
39 public void handleRequest(String request) {
40 if ("不去开班会".equals(request)) {
41 System.out.println(name + "可以处理" + request + ",给予批准!");
42 } else {
43 System.out.println(name + "不可以处理" + request + "转交给"
44 + successor.getName());
45 successor.handleRequest(request);
46 }
47 }
48 }
49
50
51 public class DaoYuan extends Handler {
52 public DaoYuan(String name) {
53 this.name = name;
54 }
55
56 public void handleRequest(String request) {
57 if ("离校".equals(request)) {
58 System.out.println(name + "可以处理" + request + "给于批准!");
59 } else {
60 System.out.println(name + "不可以处理" + request + "转交给"
61 + successor.getName());
62 successor.handleRequest(request);
63 }
64 }
65 }
66
67 public class XiaoZhang extends Handler {
68 public XiaoZhang(String name) {
69 this.name = name;
70 }
71
72 public void handleRequest(String request) {
73 if ("退学".equals(request)) {
74 System.out.println(name + "可以处理" + request + "给于批准!");
75 } else {
76 System.out.println(name + "觉的" + request + "是无理请求,不给于批准");
77 }
78 }
79 }
80 public class XueYuan {
81 private String name;
82
83 public XueYuan(String name) {
84 this.name = name;
85 }
86
87 public static void main(String[] args) {
88 HandlerWithoutPattern banzhang = new HandlerWithoutPattern("班长");
89 HandlerWithoutPattern daoyuan = new HandlerWithoutPattern("导员");
90 HandlerWithoutPattern xiaozhang = new HandlerWithoutPattern("校长");
91 //将请求给不同的人以便能够得到处理,因为客户程序不知道这些请求具体哪个
92 //人能够处理,于是它便把请求一一的交给处理者
93 banzhang.handleRequest("不去开班会");
94 daoyuan.handleRequest("不去开班会");
95 xiaozhang.handleRequest("不去开班会");
96
97 /* banzhang.handleRequest("离校");
98 daoyuan.handleRequest("离校");
99 xiaozhang.handleRequest("离校");
100
101 banzhang.handleRequest("退学");
102 daoyuan.handleRequest("退学");
103 xiaozhang.handleRequest("退学"); */
104 }
105 }
106
107
108 public class HandlerWithoutPattern {
109
110 private String name; //处理者的名字
111 public HandlerWithoutPattern(String name) {
112 this.name = name;
113 }
114 public void handleRequest(String request) {
115 if ("班长".equals(name)) {
116 if ("不去开班会".equals(request)) {
117 System.out.println(name + "可以处理" + request + ",给于批准");
118 } else {
119 System.out.println(name + "不处理" + request + "这种请求");
120 }
121 } else if ("导员".equals(name)) {
122 if ("离校".equals(request)) {
123 System.out.println(name + "可以处理" + request + ",给于批准");
124 } else {
125 System.out.println(name + "不处理" + request + "这种请求");
126 }
127 } else if ("校长".equals(name)) {
128 if ("退学".equals(request)) {
129 System.out.println(name + "可以处理" + request + ",给于批准");
130 } else {
131 System.out.println(name + "不处理" + request + "这种请求");
132 }
133 } else {
134 System.out.println("没有专人可以处理这个请求");
135 }
136 }
137
138 }
139 public class XueYuanWithPattern {
140 private String name;
141
142 public XueYuanWithPattern(String name) {
143 this.name = name;
144 }
145
146 public static void main(String[] args) {
147 Handler banzhang = new BanZhang("班长");
148 Handler laoshi = new BanZhang("老师");
149 Handler daoyuan = new DaoYuan("导员");
150 Handler xiaozhang = new XiaoZhang("校长");
151 banzhang.setNextHandler(laoshi); // 设置班长的下一个处理者是老师
152 laoshi.setNextHandler(daoyuan);// 设置老师的下一个处理者是导员
153 daoyuan.setNextHandler(xiaozhang);// 设置导员的下一个处理者是校长
154 String requests = "退学";
155 // 把请求交给班长即可,如果班长处理不了会一层层往上交
156 banzhang.handleRequest(requests);
157 }
158 }
总结:
责任链模式优点是降低了耦合、提高了灵活性。但是责任链模式可能会带来一些额外的性能损耗,因为它要从链子开头开始遍历。因为无法预知来自外界(客户端)的请求是属于哪种类型,每个类如果碰到它不能处理的请求只要放弃就可以。
缺点是效率低,因为一个请求的完成可能要遍历到最后才可能完成,当然也可以用树的概念优化。 在Java AWT1.0中,对于鼠标按键事情的处理就是使用CoR,到Java.1.1以后,就使用Observer代替CoR;扩展性差,因为在CoR中,一定要有一个统一的接口Handler.局限性就在这里。
适用场合:
•有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
•想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
•可处理一个请求的对象集合应被动态指定。
•当一个方法的传入参数将成为分支语句的判断条件,分支条件存在扩展的可能,每一个分支的职责相对独立,且逻辑较为复杂时。