【前言】 本人從事了.net開發近10年,現在從.net轉型到Java不足2月,所以所見所想都帶着很深的.net烙印,不過也有很大可能是java翻譯成.net,之后我又給轉回java了。
【責任鏈模式】
外置方式
傳統的責任鏈模式是一個請求有很多處理類,將這些處理類排列成一個順序數組,如果某一個處理類能夠處理,則中止請求;如果不能,則依次繼續請求直到全部請求完畢。
用代碼表示,就是如下所示:
1 //上下文環境 2 public class Context { 3 public String getHandlerName() { 4 return handlerName; 5 } 6 7 public void setHandlerName(String handlerName) { 8 this.handlerName = handlerName; 9 } 10 11 public String getHandlerResult() { 12 return handlerResult; 13 } 14 15 public void setHandlerResult(String handlerResult) { 16 this.handlerResult = handlerResult; 17 } 18 19 public boolean isHasHandled() { 20 return hasHandled; 21 } 22 23 public void setHasHandled(boolean hasHandled) { 24 this.hasHandled = hasHandled; 25 } 26 27 String handlerName; 28 29 String handlerResult; 30 31 boolean hasHandled; 32 33 } 34 //接口 35 public interface IOuterHandler { 36 boolean canHandler(Context context); 37 38 void handler(Context context); 39 }
1 //實現類A 2 public class AOuterHandler implements IOuterHandler { 3 4 private static String HandleName="A"; 5 6 @Override 7 public boolean canHandler(Context context) { 8 return context.getHandlerName()==HandleName; 9 } 10 11 @Override 12 public void handler(Context context) { 13 context.setHandlerResult("沒錯,就是我處理的:"+this.getClass().getSimpleName()); 14 context.setHasHandled(true); 15 } 16 } 17 18 //實現類B 19 public class BOuterHandler implements IOuterHandler { 20 private static String HandleName="B"; 21 22 @Override 23 public boolean canHandler(Context context) { 24 return context.getHandlerName()==HandleName; 25 } 26 27 @Override 28 public void handler(Context context) { 29 context.setHandlerResult("沒錯,就是我處理的:"+this.getClass().getSimpleName()); 30 context.setHasHandled(true); 31 } 32 } 33 34 //實現類C 35 public class COuterHandler implements IOuterHandler { 36 private static String HandleName="C"; 37 38 @Override 39 public boolean canHandler(Context context) { 40 return context.getHandlerName()==HandleName; 41 } 42 43 @Override 44 public void handler(Context context) { 45 context.setHandlerResult("沒錯,就是我處理的:"+this.getClass().getSimpleName()); 46 context.setHasHandled(true); 47 } 48 }
之后我們就需要將這些處理類組裝成責任鏈進行處理,具體代碼如下:
1 public class Executor { 2 public static void main(String[] args){ 3 ArrayList<IOuterHandler> handlers=getHandlers(); 4 Context context1=new Context(); 5 context1.setHandlerName("A"); 6 System.out.println(Exe(handlers,context1).getHandlerResult()); 7 8 Context context2=new Context(); 9 context2.setHandlerName("C"); 10 System.out.println(Exe(handlers,context2).getHandlerResult()); 11 } 12 13 private static ArrayList<IOuterHandler> getHandlers() { 14 ArrayList<IOuterHandler> handlers = new ArrayList<>(); 15 handlers.add(new AOuterHandler()); 16 handlers.add(new BOuterHandler()); 17 handlers.add(new COuterHandler()); 18 return handlers; 19 } 20 21 private static Context exe(ArrayList<IOuterHandler> handlers,Context context){ 22 if(handlers!=null&&handlers.size()!=0){ 23 handlers.forEach(handler->{ 24 if(context.isHasHandled()){ 25 return; 26 } 27 if(handler.canHandler(context)){ 28 handler.handler(context); 29 } 30 }); 31 } 32 return context; 33 } 34 }

我們可以看見,exe方法就是實現的主體(這里用了foreach函數,所以沒有進行短路處理,實際上如果context.isHasHandled==true后,沒有必要進行后面的循環),原則就是當前類是否能夠處理,如果不能,就交付給下一個處理函數,當然可能是到最后也沒有被處理,這種情況可以不處理直接返回,也可能是使用默認處理函數,不過這不重要了。這種處理方式是存在缺陷的,就是倆個handler想聯合處理,是做不到的。所以責任鏈模式,就發展出內置的形式。
內置方式
內置方式還是看代碼:
//Contenx略,見上文 public interface IInnerHandler { void setHandler(IInnerHandler handler); void hanlder(Context context); }
1 //類A 2 public class AInnerHandler implements IInnerHandler { 3 private static String HandleName="A"; 4 private IInnerHandler handler; 5 6 @Override 7 public void setHandler(IInnerHandler handler) { 8 this.handler=handler; 9 } 10 11 @Override 12 public void hanlder(Context context) { 13 if(context.getHandlerName().equals(HandleName)){ 14 context.setHandlerResult("沒錯,就是我處理的:"+this.getClass().getSimpleName()); 15 //不需要這句,因為沒有意義了 16 //context.setHasHandled(true); 17 }else { 18 handler.hanlder(context); 19 } 20 } 21 22 //類B 23 public class BInnerHandler implements IInnerHandler { 24 private static String HandleName="A"; 25 private static String HandleName2="C"; 26 private IInnerHandler handler; 27 28 @Override 29 public void setHandler(IInnerHandler handler) { 30 this.handler=handler; 31 } 32 33 @Override 34 public void hanlder(Context context) { 35 if(HandleName.equals(context.getHandlerName())||HandleName2.equals(context.getHandlerName())){ 36 for (int i=0;i<3;i++){ 37 handler.hanlder(context); 38 } 39 } 40 } 41 } 42 //類C 43 44 public class CInnerHandler implements IInnerHandler { 45 private static String HandleName="C"; 46 private IInnerHandler handler; 47 48 @Override 49 public void setHandler(IInnerHandler handler) { 50 this.handler=handler; 51 } 52 53 @Override 54 public void hanlder(Context context) { 55 if(context.getHandlerName().equals(HandleName)){ 56 String resultInfo="***沒錯,就是我處理的:"+this.getClass().getSimpleName(); 57 if(context.getHandlerResult()==null){ 58 context.setHandlerResult(resultInfo); 59 }else { 60 context.setHandlerResult(context.getHandlerResult() + "\n" + resultInfo); 61 } 62 }else { 63 handler.hanlder(context); 64 } 65 } 66 }
之后我們將內置實現類組合實現責任鏈處理
1 public class Executor { 2 public static void main(String[] args){ 3 IInnerHandler handler=getHandler(); 4 5 Context context1=new Context(); 6 context1.setHandlerName("A"); 7 handler.hanlder(context1); 8 System.out.println(context1.getHandlerResult()); 9 10 Context context2=new Context(); 11 context2.setHandlerName("C"); 12 handler.hanlder(context2); 13 System.out.println(context2.getHandlerResult()); 14 } 15 16 private static IInnerHandler getHandler() { 17 IInnerHandler aHandler=new AInnerHandler(),bHandler=new BInnerHandler(),cHandler=new CInnerHandler(); 18 bHandler.setHandler(cHandler); 19 aHandler.setHandler(bHandler); 20 return aHandler; 21 } 22 }
處理的結果如下:

我們可以看見,內置完全不同於外置,對於A、C類來說,他的作用就是處理,如果處理不了讓下一個類處理,這和外置是類似的。但是B類,他可以自己處理,也可以和A,C聯合處理。本例中,B就自己未做處理,只是讓C處理了三次。所以明顯可以看出內置功能更加強大。但是等等,像B,C這種組合,明顯是裝飾者模式,怎么是責任鏈呢?
【裝飾者模式】
什么是裝飾者?還是看代碼吧
1 //上下文 2 public class Context { 3 private ArrayList<String> arrayList=new ArrayList<String>(); 4 public ArrayList<String> getArrayList(){ 5 return arrayList; 6 } 7 public void add(String moreInfo){ 8 arrayList.add(moreInfo); 9 } 10 } 11 //裝飾者接口 12 public interface IDecorator { 13 void setDecorator(IDecorator decorator); 14 15 void domore(Context context); 16 }
1 //ADecorator 2 public class ADecorator implements IDecorator { 3 IDecorator decorator; 4 5 public void setDecorator(IDecorator decorator) { 6 this.decorator = decorator; 7 } 8 9 public void domore(Context context) { 10 context.add(this.getClass().getSimpleName()); 11 decorator.domore(context); 12 context.add(this.getClass().getSimpleName()); 13 } 14 } 15 16 // BDecorator 17 public class BDecorator implements IDecorator { 18 IDecorator decorator; 19 20 public void setDecorator(IDecorator decorator) { 21 this.decorator = decorator; 22 } 23 24 public void domore(Context context) { 25 context.add(this.getClass().getSimpleName()); 26 decorator.domore(context); 27 context.add(this.getClass().getSimpleName()); 28 } 29 } 30 31 //CDecorator 32 public class CDecorator implements IDecorator { 33 IDecorator decorator; 34 35 public void setDecorator(IDecorator decorator) { 36 this.decorator = decorator; 37 } 38 39 public void domore(Context context) { 40 context.add(this.getClass().getSimpleName()); 41 //decorator.domore(context); 42 context.add("最后一項需要短路"); 43 context.add(this.getClass().getSimpleName()); 44 } 45 }
裝飾者裝配和執行的代碼如下:
1 public class Executor { 2 public static void main(String[] args) { 3 IDecorator decorator = getDecorator(); 4 Context context = new Context(); 5 decorator.domore(context); 6 context.getArrayList().forEach(mesage -> System.out.println(mesage)); 7 } 8 9 private static IDecorator getDecorator() { 10 IDecorator ade = new ADecorator(), 11 bad = new BDecorator(), 12 cad = new CDecorator(); 13 bad.setDecorator(cad); 14 ade.setDecorator(bad); 15 return ade; 16 } 17 }
執行的結果:

【對比】
責任鏈(外置):有一個類負責任,在找到這個負責的類之前,其他的類都是看一樣是否和自己有關。而找到這個負責的類后,一般也會短路,不會繼續往下執行。所以從責任鏈重點在於誰負責。
裝飾者:在構成的鏈路中,每一個類都發揮自己的作用,並且不會進行短路,直到最后一個類。
責任鏈(內置):和裝飾者在接口層面,出來名字不同,沒有什么不一樣的。所以它是用裝飾者的身體,裝責任鏈的思想。是一個雜交體。至於是責任鏈還是裝飾者,就看內部實現是否有短路,是否有具體負責任的。很可能是倆個都有。
【思考】
責任鏈和裝飾者這種變形,是否是java中常用的,是否有其他變形的實現呢?答案是有,下節將讓你看見不一樣的責任鏈(裝飾者)。
