委托在觀察者模式中的java實現

最近在看《大話設計模式》這本書,書中內容淺顯易懂,遺憾的是,書中的代碼實現用的是c#,雖然作為java程序員能看懂大致的意思,但是在遇到委托這樣的語言級別隔閡的時候,還是感覺很吃力。那么在c#中一行代碼就能實現的委托,在java中怎么實現呢?

本文參考觀察者設計模式 Vs 事件委托(java)

一:為什么要在觀察者模式中使用委托

觀察者模式如果不使用委托,就面臨著觀察者需要通過實現接口來統一update方法。這對于已經封裝完成的功能來說,要求過于苛刻。那么如果在觀察者模式中使用委托,就可以擺脫掉實現接口統一方法的必要,從而完成真正意義上的類與類之間的解耦,滿足開閉原則。

二:委托在觀察者模式中的實現原理。

java中的委托說到底還是通過反射來實現。當觀察者(observer)需要訂閱某一主題(subject)時,之前是僅需要傳遞觀察者對象本身,而此時要使用委托,就額外需要傳遞觀察者接到通知后需要調用的方法名稱以及方法需要的實際參數。形如

notifier.addListener(doa, "doaUpdate", 123,"spring");

第一個參數是觀察者自己,第二個參數字符串就是需要傳遞的方法名,第三個就是需要傳遞的實際參數組成的數組。反射正是通過這樣的訂閱獲得了需要的類名,方法名和參數類型,從而實現了反射,實現了不需要接口統一方法名稱就可以動態實現通知。

三:委托在java中的代碼實現。

1:Event事件類

主要是通過獲取到的類名,方法名,參數類型完成反射調用

public class Event {
    private Object object;
    private String methodName;
    private Object [] params;
    private Class [] paramTypes;
    
    public Event(Object object,String methodName,Object...objects ){
        this.object=object;
        this.methodName=methodName;
        this.params=objects;
        contractParamTypes(this.params);
    }

    private void contractParamTypes(Object [] params){
        if(params==null){
            return;
        }
        paramTypes=new Class[params.length];
        for(int i=0;i<params.length;i++){
            paramTypes[i]=params[i].getClass();
        }
    }
    
    // EventHandler通過nofityx()調用該方法,
    //該方法通拿到每一個具體的傳入的對象和傳入的方法名,經過反射調用對應的方法
    public void invoke() throws Exception{
        Method method =object.getClass().getMethod(methodName, paramTypes);
        if(method==null){
            
        }else{
            method.invoke(object, params);
        }
    }

}
2:EventHandler

主要用來保存觀察者,以及提供通知觀察者的方法。

public class EventHandler {
    private List<Event> objects;
    
    public EventHandler(){
        objects=new ArrayList<Event>();
        
    }
    
    public void addEvent(Object object,String methodName,Object...args){
        Event event=new Event(object,methodName,args);
        objects.add(event);
    }
    
    public void notifyx() throws Exception{
        for(Event e:objects){
            // 通過反射調用對應的方法
            e.invoke();
        }
    }
}

上面的objects.add(event)實際上就是在保存傳進來的觀察者。

3:Notifier

提供了訂閱的抽象主題,主題持有EventHandler,用來傳遞參數給Event,以及提供了何時調用通知的抽象方法。

public abstract class Notifier {

    private EventHandler eventHandler=new EventHandler();
    
    public EventHandler getEventHandler() {
        return eventHandler;
    }
  
    public  void addListener(Object object,String methodName,Object...args){
        //講傳遞進來的參數交由EventHandler,EventHandler交由event處理。
            eventHandler.addEvent(object, methodName, args);
    }
    //具體的實現類規定了何時開始通知觀察者。
    public abstract void notifyx();
}
4:GoodNofitier

只關心何時需要通知觀察者就可以了。

public class GoodNofitier extends Notifier{
    @Override
     public  void notifyx(){
        try {
            getEventHandler().notifyx();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }   
}
5:具體的觀察者
public class DeleObserverA {

    public void doaUpdate(int name,String month){
        System.out.println("DeleObserverA 開始更新:"+name+":"+month);
    }
}


public class DeleObserverB {
    public void dobUpdate(int name,String month){
        System.out.println("DeleObserverB 開始更新:"+name+":"+month);
    }
}
6:main方法調用
//委托 觀察者
Notifier notifier=new GoodNofitier();
DeleObserverA doa=new DeleObserverA();
DeleObserverB dob=new DeleObserverB();
Student studnet=new Student();
//      notifier.addListener(doa, "doaUpdate", new Object[]{123,"spring"});
//      notifier.addListener(dob, "dobUpdate", new Object[]{456,"summer"});
notifier.addListener(doa, "doaUpdate", 123,"springg");
notifier.addListener(dob, "dobUpdate", 456,"summerr");

notifier.notifyx();
7:JDK8反射時int類型參數導致NoSuchMethodException
java.lang.NoSuchMethodException: observer.delete.DeleObserverA.doaUpdate(java.lang.Integer, java.lang.String)
    at java.lang.Class.getMethod(Class.java:1786)
    at observer.delete.Event.invoke(Event.java:31)
    at observer.delete.EventHandler.notifyx(EventHandler.java:22)
    at observer.delete.GoodNofitier.notifyx(GoodNofitier.java:9)
    at factorymode.MainActivity.main(MainActivity.java:139)

這個時候我們只需要把具體觀察者的方法中的int改為Integer類型就可以了。

public class DeleObserverA {

    public void doaUpdate(Integer name,String month){
        System.out.println("DeleObserverA 開始更新:"+name+":"+month);
    }
}

這樣就實現了委托在觀察者模式中的使用。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容

  • 1 場景問題# 1.1 訂閱報紙的過程## 來考慮實際生活中訂閱報紙的過程,這里簡單總結了一下,訂閱報紙的基本流程...
    七寸知架構閱讀 4,641評論 5 57
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,786評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,666評論 25 708
  • 我要寫一串文字來紀念我年少的輕狂,可能是亂七八糟、毫無頭緒的,沒什么寫作技巧,我就是隨心寫,看明白就好了,...
    劉芋圓的西瓜味雪糕閱讀 521評論 0 3
  • 作為一個小散,最重要的是應該避免散戶思維。總是寄希望于虧損的恢復盈利,卻不去觀察那些發展潛力大的牛股總是一騎絕塵,...
    kasitravel閱讀 469評論 0 0