JAVA實現事件委託模式


本文爲轉載(http://blog.csdn.net/yanshujun/article/details/6494447)文章(我在原文的基礎上進行了修改)

閱讀之前可參考 大話設計模式中的觀察者模式(我是在學習觀察者模式中,查閱到轉載的這篇文章的


java實現事件委託模式:


結構圖---草圖:



事件委託模式是一個比較常用的設計模式,但是Java語言本身沒有對其做一定的封裝,因此實現起來有一定難度(瞭解原理後很簡單),相比之下.NET(.Net中有delegate委託實現)就容易了很多。

身爲一個Java愛好者,怎麼向這樣一個小困難低頭,但是上網搜索,卻沒發現相關解決方案,得,自己來做一個封裝吧。

其實結合例子更好,那麼我就用一個小例子來引出這種設計模式。

場景模擬:

一個班級,有兩類學生,A類:不學習,玩,但是玩的東西不一樣,有的是做遊戲,與的是看電視(有點不合理)

B類:放哨的學生,專門看老師的動向,如果老師進班了就立即通知大家。

如此就形成了一個需求,放哨的學生要通知所有玩的學生:老師來了,而不同的學生有不同的反應,有的馬上把電視關閉,有的停止玩遊戲。

設計的要求如下,讓A類學生和B類學生完全解耦,即A類完全不知道B類的學生,卻可以通知B類的學生。

代碼及說明如下:

Event 類,定義了一個事件類:

Code:
  1. package lnurd.test;   
  2.   
  3. import java.lang.reflect.Method;   
  4. import java.util.Date;   
  5.   
  6. public class Event {   
  7.     //要執行方法的對象   
  8.     private Object object;   
  9.     //要執行的方法名稱   
  10.     private String methodName;   
  11.     //要執行方法的參數   
  12.     private Object[] params;   
  13.     //要執行方法的參數類型   
  14.     private Class[] paramTypes;   
  15.        
  16.     public Event(){   
  17.            
  18.     }   
  19.     public Event(Object object,String methodName,Object...args){   
  20.         this.object=object;   
  21.         this.methodName=methodName;   
  22.         this.params=args;   
  23.         contractParamTypes(this.params);   
  24.     }   
  25.     //根據參數數組生成參數類型數組   
  26.     private void contractParamTypes(Object[] params){   
  27.         this.paramTypes=new Class[params.length];   
  28.         for(int i=0;i<params.length;i++){   
  29.             this.paramTypes[i]=params[i].getClass();   
  30.         }   
  31.     }   
  32.        
  33.     public Object getObject() {   
  34.         return object;   
  35.     }   
  36.     //若干setter getter省略   
  37.     //...
  38.     public void setParamTypes(Class[] paramTypes) {   
  39.         this.paramTypes = paramTypes;   
  40.     }   
  41.     //執行該 對象的該方法(反射)   
  42.     public void invoke() throws Exception{   
  43.         Method method=object.getClass().getMethod(this.getMethodName(), this.getParamTypes());   
  44.         if(null==method){   
  45.             return;   
  46.         }   
  47.         method.invoke(this.getObject(), this.getParams());   
  48.     }   
  49. }  

EventHandler類,若干Event類的載體,同時提供一個執行所有Event(遍歷)的方法

Code:
  1. package lnurd.test;   
  2.   
  3. import java.util.ArrayList;   
  4. import java.util.List;   
  5.   
  6. public class EventHandler {   
  7.     //是用一個List   
  8.     private List<Event> objects;   
  9.        
  10.     public EventHandler(){   
  11.         objects=new ArrayList<Event>();   
  12.     }   
  13.     //添加某個對象要執行的事件,及需要的參數   
  14.     public void addEvent(Object object,String methodName,Object...args){   
  15.         objects.add(new Event(object,methodName,args));   
  16.     }   
  17.     //通知所有的對象執行指定的事件   
  18.     public void notifyX() throws Exception{   
  19.         for(Event e : objects){
  20.    //反射調用對象的方法
  21.             e.invoke();   
  22.         }   
  23.     }   
  24. }  

放哨的學生(被觀察者):這裏先抽象出一個抽象類,因爲放哨的人有盡職盡責的,也有馬馬虎虎的,

但是他們有功能的方法:

1、增加需要幫忙放哨的學生  

2、通知所有需要放哨的學生:老師來了

Code:
  1. package lnurd.test;   
  2. //被觀察者(主題-訂閱中的 主題)
  3. public abstract class Notifier {   
  4.     //持有(事件處理)的聚集(直接實例化,也可放在構造器中)
  5.     private EventHandler eventHandler=new EventHandler();   
  6.        
  7.     public EventHandler getEventHandler() {   
  8.         return eventHandler;   
  9.     }   
  10.     public void setEventHandler(EventHandler eventHandler) {   
  11.         this.eventHandler = eventHandler;   
  12.     }   
  13.     //增加需要幫忙放哨的學生 ()  
  14.     public abstract void addListener(Object object,String methodName,Object...args);   
  15.     //告訴所有要幫忙放哨的學生:老師來了   
  16.     public abstract void notifyX();   
  17. }  

接着是放哨人的具體實現了,這裏僅實現兩個

1、盡職盡責的放哨人GoodNotifier

2、馬馬虎虎的放哨人BadNotifier

Code:
  1. package lnurd.test;   
  2.   
  3. public class GoodNotifier extends Notifier {   
  4.   
  5.     @Override  
  6.     public void addListener(Object object, String methodName, Object... args) {   
  7.         System.out.println("有新的同學委託盡職盡責的放哨人!");   
  8.         this.getEventHandler().addEvent(object, methodName, args);   
  9.     }   
  10.   
  11.     @Override  
  12.     public void notifyX() {   
  13.         System.out.println("盡職盡責的放哨人告訴所有需要幫忙的同學:老師來了");   
  14.         try{   
  15.             this.getEventHandler().notifyX();   
  16.         }catch(Exception e){   
  17.             e.printStackTrace();   
  18.         }   
  19.     }   
  20.   
  21. }   
  22.   
  23. //對於BadNotifier代碼類似,不再複述.  

接下來是玩遊戲的學生(觀察者):PlayingGameListener

Code:
  1. package lnurd.test;   
  2.   
  3. import java.util.Date;   
  4.   
  5. public class PlayingGameListener {   
  6.     public PlayingGameListener(){   
  7.         System.out.println("我正在玩遊戲 開始時間"+new Date());   
  8.     }   
  9.     public void stopPlayingGame(Date date){   
  10.         System.out.println("老師來了,快回到座位上,結束時間"+date);   
  11.     }   
  12. }  

 

在接下來是看電視的學生觀察者WatchingTVListener

Code:
  1. package lnurd.test;   
  2.   
  3. import java.util.Date;   
  4.   
  5. public class WatchingTVListener {   
  6.     public WatchingTVListener(){   
  7.         System.out.println("我正在看電視 "+new Date());   
  8.     }   
  9.     public void stopWatchingTV(Date date){   
  10.         System.out.println("老師來了,快關閉電視 。 結束時間"+date);   
  11.     }   
  12. }  

測試代碼:

Code:
  1. //創建一個盡職盡責的放哨者   
  2. Notifier goodNotifier=new GoodNotifier();   
  3.   
  4. //創建一個玩遊戲的同學,開始玩遊戲   
  5. PlayingGameListener playingGameListener=new PlayingGameListener();   
  6. //創建一個看電視的同學,開始看電視   
  7. WatchingTVListener watchingTVListener=new WatchingTVListener();   
  8. //玩遊戲的同學告訴放哨的同學,老師來了告訴一下   
  9. goodNotifier.addListener(playingGameListener, "stopPlayingGame",new Date());   
  10. //看電視的同學告訴放哨的同學,老師來了告訴一下   
  11. goodNotifier.addListener(watchingTVListener, "stopWatchingTV",new Date());   
  12. try{   
  13.     //一點時間後   
  14.     Thread.sleep(1000);   
  15. }catch(Exception e){   
  16.     e.printStackTrace();   
  17. }   
  18. //老師出現,放哨的人通知所有要幫忙的同學:老師來了   
  19. goodNotifier.notifyX();  

點評:

1、放哨者完全不知道做遊戲者的存在,完全解耦。(當然,功勞歸功於Event和EventHandler,且這兩個類具有通用性)

2、老師來了後遊戲者停止遊戲回到座位,看電視着關閉電視。(一次通知,執行了不同類的不同方法)

3、擴展性很高,再來一個打籃球的學生就先寫個打籃球學生類,並在測試代碼中告訴放哨者一下就好,放哨者完全沒有變。重用性好

PS:寫文檔是在太累了,是寫代碼的好幾倍,其實應該將Event 和EventHandler抽象成接口最後,實在太晚了,留給大家發揮吧。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章