責任鏈與裝飾者模式(基本介紹)【設計模式1】


【前言】 本人從事了.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中常用的,是否有其他變形的實現呢?答案是有,下節將讓你看見不一樣的責任鏈(裝飾者)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM