设计模式:责任链模式
一、前言
责任链(chain of responsibility)模式很像异常的捕获和处理,当一个问题发生的时候,当前对象看一下自己是否能够处理,不能的话将问题抛给自己的上级去处理,但是要注意这里的上级不一定指的是继承关系的父类,这点和异常的处理是不一样的。所以可以这样说,当问题不能解决的时候,将问题交给另一个对象去处理,就这样一直传递下去直至当前对象找不到下线了,处理结束。如下图所示,处于同等层次的类都继承自Support类,当当前对象不能处理的时候,会根据预先设定好的传递关系将问题交给下一个人,可以说是“近水楼台先得月”,就看有没有能力了。我们也可以看作是大家在玩一个传谜语猜谜底的小游戏,按照座位的次序以及规定的顺序传递,如果一个人能回答的上来游戏就结束,否则继续向下传,如果所有人都回答不出来也会结束。这样或许才是责任链的本质,体现出了同等级的概念。
二、代码
Trouble 类:(数据结构)
1 package zyr.dp.cor; 2 3 public class Trouble { 4 5 private int number; 6 public Trouble( int number){ 7 this.number=number; 8 } 9 public int getNumber() { 10 return number; 11 } 12 public String toString(){ 13 return "问题编号:["+number+"]"; 14 } 15 }
Support 类:(抽象类,使用了模板方法)
1 package zyr.dp.cor; 2 3 public abstract class Support { 4 5 protected abstract boolean resolve(Trouble trouble); 6 7 String name; 8 Support next; 9 10 public Support(String name){ 11 this.name=name; 12 } 13 14 public String toString() { 15 return "对象:<"+name+">"; 16 } 17 18 public Support setAndReturnNext(Support next){ 19 this.next=next; 20 return next; 21 } 22 23 public final void support(Trouble trouble){ 24 if(resolve(trouble)){ 25 done(trouble); 26 }else if(next!=null){ 27 next.support(trouble); 28 }else{ 29 fail(trouble); 30 } 31 } 32 33 protected void fail(Trouble trouble) { 34 System.out.println(this+"解决问题失败,"+trouble); 35 } 36 37 protected void done(Trouble trouble) { 38 System.out.println(this+"已经解决问题,"+trouble); 39 } 40 41 }
NoSupport 类:
1 package zyr.dp.cor; 2 3 public class NoSupport extends Support { 4 5 public NoSupport(String name) { 6 super(name); 7 } 8 9 protected boolean resolve(Trouble trouble) { 10 return false; 11 } 12 13 }
OddSupport 类:
1 package zyr.dp.cor; 2 3 public class OddSupport extends Support { 4 5 public OddSupport(String name) { 6 super(name); 7 } 8 9 protected boolean resolve(Trouble trouble) { 10 return (trouble.getNumber()%2) == 1 ? true : false; 11 } 12 13 }
SpecialSupport 类:
1 package zyr.dp.cor; 2 3 public class SpecialSupport extends Support { 4 5 public int specialNumber; 6 public SpecialSupport(String name,int specialNumber) { 7 super(name); 8 this.specialNumber= specialNumber; 9 } 10 11 protected boolean resolve(Trouble trouble) { 12 return trouble.getNumber()==specialNumber ? true : false; 13 } 14 15 }
LimitSupport 类:
1 package zyr.dp.cor; 2 3 public class LimitSupport extends Support { 4 5 private int limit; 6 public LimitSupport(String name,int limit) { 7 super(name); 8 this.limit=limit; 9 } 10 11 protected boolean resolve(Trouble trouble) { 12 return trouble.getNumber()<=limit? true : false; 13 } 14 15 }
Main类:
1 package zyr.dp.cor; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 Support limitSupportLess = new LimitSupport("有限支持小",5); 7 Support limitSupportMore = new LimitSupport("有限支持大",15); 8 Support oddSupport = new OddSupport("奇数支持"); 9 Support specialSupport = new SpecialSupport("特定支持",36); 10 Support noSupport = new NoSupport("没有支持"); 11 limitSupportLess.setAndReturnNext(limitSupportMore).setAndReturnNext(oddSupport).setAndReturnNext(specialSupport).setAndReturnNext(noSupport); 12 System.out.println("===<有限支持小>尝试解决问题==="); 13 for(int i=0;i<40;i++){ 14 limitSupportLess.support(new Trouble(i)); 15 } 16 System.out.println("===<特定支持>尝试解决问题==="); 17 for(int i=0;i<40;i++){ 18 specialSupport.support(new Trouble(i)); 19 } 20 21 } 22 23 }
运行结果:
1 ===<有限支持小>尝试解决问题=== 2 对象:<有限支持小>已经解决问题,问题编号:[0] 3 对象:<有限支持小>已经解决问题,问题编号:[1] 4 对象:<有限支持小>已经解决问题,问题编号:[2] 5 对象:<有限支持小>已经解决问题,问题编号:[3] 6 对象:<有限支持小>已经解决问题,问题编号:[4] 7 对象:<有限支持小>已经解决问题,问题编号:[5] 8 对象:<有限支持大>已经解决问题,问题编号:[6] 9 对象:<有限支持大>已经解决问题,问题编号:[7] 10 对象:<有限支持大>已经解决问题,问题编号:[8] 11 对象:<有限支持大>已经解决问题,问题编号:[9] 12 对象:<有限支持大>已经解决问题,问题编号:[10] 13 对象:<有限支持大>已经解决问题,问题编号:[11] 14 对象:<有限支持大>已经解决问题,问题编号:[12] 15 对象:<有限支持大>已经解决问题,问题编号:[13] 16 对象:<有限支持大>已经解决问题,问题编号:[14] 17 对象:<有限支持大>已经解决问题,问题编号:[15] 18 对象:<没有支持>解决问题失败,问题编号:[16] 19 对象:<奇数支持>已经解决问题,问题编号:[17] 20 对象:<没有支持>解决问题失败,问题编号:[18] 21 对象:<奇数支持>已经解决问题,问题编号:[19] 22 对象:<没有支持>解决问题失败,问题编号:[20] 23 对象:<奇数支持>已经解决问题,问题编号:[21] 24 对象:<没有支持>解决问题失败,问题编号:[22] 25 对象:<奇数支持>已经解决问题,问题编号:[23] 26 对象:<没有支持>解决问题失败,问题编号:[24] 27 对象:<奇数支持>已经解决问题,问题编号:[25] 28 对象:<没有支持>解决问题失败,问题编号:[26] 29 对象:<奇数支持>已经解决问题,问题编号:[27] 30 对象:<没有支持>解决问题失败,问题编号:[28] 31 对象:<奇数支持>已经解决问题,问题编号:[29] 32 对象:<没有支持>解决问题失败,问题编号:[30] 33 对象:<奇数支持>已经解决问题,问题编号:[31] 34 对象:<没有支持>解决问题失败,问题编号:[32] 35 对象:<奇数支持>已经解决问题,问题编号:[33] 36 对象:<没有支持>解决问题失败,问题编号:[34] 37 对象:<奇数支持>已经解决问题,问题编号:[35] 38 对象:<特定支持>已经解决问题,问题编号:[36] 39 对象:<奇数支持>已经解决问题,问题编号:[37] 40 对象:<没有支持>解决问题失败,问题编号:[38] 41 对象:<奇数支持>已经解决问题,问题编号:[39] 42 ===<特定支持>尝试解决问题=== 43 对象:<没有支持>解决问题失败,问题编号:[0] 44 对象:<没有支持>解决问题失败,问题编号:[1] 45 对象:<没有支持>解决问题失败,问题编号:[2] 46 对象:<没有支持>解决问题失败,问题编号:[3] 47 对象:<没有支持>解决问题失败,问题编号:[4] 48 对象:<没有支持>解决问题失败,问题编号:[5] 49 对象:<没有支持>解决问题失败,问题编号:[6] 50 对象:<没有支持>解决问题失败,问题编号:[7] 51 对象:<没有支持>解决问题失败,问题编号:[8] 52 对象:<没有支持>解决问题失败,问题编号:[9] 53 对象:<没有支持>解决问题失败,问题编号:[10] 54 对象:<没有支持>解决问题失败,问题编号:[11] 55 对象:<没有支持>解决问题失败,问题编号:[12] 56 对象:<没有支持>解决问题失败,问题编号:[13] 57 对象:<没有支持>解决问题失败,问题编号:[14] 58 对象:<没有支持>解决问题失败,问题编号:[15] 59 对象:<没有支持>解决问题失败,问题编号:[16] 60 对象:<没有支持>解决问题失败,问题编号:[17] 61 对象:<没有支持>解决问题失败,问题编号:[18] 62 对象:<没有支持>解决问题失败,问题编号:[19] 63 对象:<没有支持>解决问题失败,问题编号:[20] 64 对象:<没有支持>解决问题失败,问题编号:[21] 65 对象:<没有支持>解决问题失败,问题编号:[22] 66 对象:<没有支持>解决问题失败,问题编号:[23] 67 对象:<没有支持>解决问题失败,问题编号:[24] 68 对象:<没有支持>解决问题失败,问题编号:[25] 69 对象:<没有支持>解决问题失败,问题编号:[26] 70 对象:<没有支持>解决问题失败,问题编号:[27] 71 对象:<没有支持>解决问题失败,问题编号:[28] 72 对象:<没有支持>解决问题失败,问题编号:[29] 73 对象:<没有支持>解决问题失败,问题编号:[30] 74 对象:<没有支持>解决问题失败,问题编号:[31] 75 对象:<没有支持>解决问题失败,问题编号:[32] 76 对象:<没有支持>解决问题失败,问题编号:[33] 77 对象:<没有支持>解决问题失败,问题编号:[34] 78 对象:<没有支持>解决问题失败,问题编号:[35] 79 对象:<特定支持>已经解决问题,问题编号:[36] 80 对象:<没有支持>解决问题失败,问题编号:[37] 81 对象:<没有支持>解决问题失败,问题编号:[38] 82 对象:<没有支持>解决问题失败,问题编号:[39]
我们可以看到同等级的对象,按照自己被添加的次序来安排,这点非常重要,在实际应用中,我们都是将解答能力最弱的类放到最前面,然后一点点加强,这样可以使得解答能力比较弱的类有机会去解答,正如我们的例子,如果让解答能力强的类直接去处理问题,能够处理就不回传给下一个了,当然我们也看到这里面有的类能力有限,有的类和其他类的能力有重叠部分,当然也有所有类都解决不了的问题。
通过责任链,我们可以将问题与处理问题的对象分离出来,特别适合用于不知道发生的问题到底是什么(有很多选择)但是又必须处理的情况(按照每个选择情况设计相应的处理类),这样就弱化了请求问题的人和回答问题的人的关系,如果不得不让发出请求的人知道处理请求的人,这样就不利于代码的复用,因为需要在请求问题的对象之中调用处理请求的对象,而使用责任链模式就能很好的规避这一点,便于将这部分代码独立出来,当做组件使用,符合开闭原则。
同样的我们看到在责任链中使用了模板方法,在父类中抽象的定义了将要处理的流程,使得扩充起来非常方便,修改起来也很方便。利用委托的思想,不过这次是自己使用自己,通过责任链,其实就是一个链表,来处理问题是非常好的一种思想。可以动态地修改责任链,同时也使得每个责任链上的对象可以专注于自己的问题,这样思路清晰,便于扩展,但是使用责任链模式因为不断地调用能够处理某个问题的对象(遍历链表)和直接就能知道谁去处理的方式相比肯定会出现延迟,这就需要一个取舍了。
最后,我们要注意,resolve()的属性是protected,这样做的好处是可以让同一个包或者子类使用该方法,而不会让其他包的类使用,因为解决问题的方法就应该是子类使用的,这样可以使得该方法不被误用。而将失败和成功方法设为protected,也是可以让子类去继承和修改,而不让其他包中的类使用,对于support()方法就是可以让其他包使用的,因此使用public,这一点可以看出写代码的严谨度。
三、总结
责任链使用了模板方法和委托的思想构建了一个链表,通过遍历链表来一个个询问链表中的每一个节点谁可以处理某件事情,如果某个节点能够胜任,则直接处理,否则继续向下传递,如果都不能处理next==null,则处理结束。责任链会造成处理的时延,但是能够解耦合,提高可扩展性,使得处理方法的类更专注于处理把自己的事情,便于扩展和改变处理的优先级,应用也非常的广泛。