<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    lyl3333489

    觀察者模式

        常聽說這么一句話(大意是這樣):不必可以去套用設計模式,如果按照面向對象的基本原則編程,自然是優雅的設計,即使沒有刻意使用模式,設計也會近乎于模式。開始感覺有一點玄,但在看了《C#設計模式縱橫談》視頻后,覺得有所收獲。下面,就參考視頻的內容,嘗試著寫這么一個過程:根據面向對象的一般原則對設計進行重構,逐漸演化出觀察者模式。
    涉及的面向對象設計原則:單一職責原則、封裝變化、面向接口編程、依賴倒置原則、開閉原則。

    1.發布訂閱模型:



             
                   
    假如有需求如下:

    銀行需要把帳戶的如匯款、轉賬或取款等操作通知用戶,途徑包括手機短信、 email等。如圖所式。

    自然地,我們可以這樣做:

    public class ATM
     {
         BankAccount bankAccount;
         
         
    public void process()
         {
              
    //bankAccount...
             this.sendEmail(userEmail);
             
    this.sendPhone(phoneNumber);
         }
     
         
    private void sendEmail(String userEmail)
         {
             
    //
         }

        
    private void sendMobile(String phoneNumber)
         {
             
    //
         }
     }

    ATM機的 process()方法在處理完業務邏輯后,由email和phone通知用戶。

    2.初步重構

    好像有bad smells,恩,根據單一職責原則。新增Email類和Phone類,并把相關業務邏輯改到BankAccount類完成。于是我們的代碼可以這樣:


    public class ATM
    {
        BankAccount bankAccount;
        
        
        
    public void process()
        {
              
    //
              bankAccount.withDraw();
        }
     
     }

    public class BankAccount 
    {
        Email email;
        Mobile mobile;

        
    public void withDraw()
        {
             
    //
             email.sendEmail(userEmail);
             mobile.sendMobile(phoneNumber);
        }
    }

    public class Email
    {
        
    public void sendEmail(String userEmail)
        {
        }
    }

    public class Mobile
    {
        
    public void sendMobile(String phoneNumber)
        {
        }
    }

    下面是代碼的UML圖:




    3.擁抱變化

    這個解決方案有問題嗎?可能沒有問題。它實現了我們的需求:在帳戶有操作變動的時候,通知Email和Mobile去發送信息給用戶。但這樣設計就足夠了嗎?可能足夠了,可能還不夠。
    考慮如下兩種情況:
    1.在很長一段時間里,訂閱方式很穩定,比如系統只通過郵件和手機短信進行信息訂閱,那么這個實現沒有太大問題;
    2.在近一兩年或更短的時間,更多的訂閱方式將會源源不斷地被加進來:比如可以登錄官方網站等等,那這個實現就有問題:再看一下我們的UML圖,類BankAccount依賴于Email和Mobile類!就是說,如果需要添加新的訂閱方式ATM類的process()方法勢必要重新設計!

    于是我們的BankAccount類不得不變成:

    public class  BankAccount
    {
        Email email;
        Mobile mobile;
        Web web;

        
    public void withDraw()
        {
              
    //
             email.sendEmail(userEmail);
             mobile.sendMobile(phoneNumber);
             web.sendWeb(webSite);
        }
     
     }

    如果還有另一種方式,那么process()方法就又會需要加入:otherSubscribe.send...();等方法,另外如果訂閱類的接口(這里指sendEmail等方法)發生變化,BankAccount的withDraw()方法也必須有相應的變化!這當然是種災難。我們必須改變這種情況。
    先解決遺留問題:第一種情況:訂閱方式相對穩定的情況下呢?不改動會產生災難嗎?
    個人認為:不會。比如某個系統信息只通過手機短信訂閱,那就沒有必要太在意這個問題??紤]周全一點不好嗎,如果將來有類似需求呢?小心過度設計!為了將來可能出現需求而進行的預先設計并不太好。有需求,才有設計。

    現在來看解決之道:

    運用面向對象的思想,抽象出問題所在。BankAccount類依賴于 Email類和Mobile類,而Email和Mobile是具體的類,ATM依賴于具體的類了,而且還不止一個!回憶一下依賴倒置原則:具體應該依賴于抽象,底層模式應該依賴于高層模式。那怎么實現依賴倒置原則呢?面向對象編程中有一條總的原則:封裝變化。如何實現封裝變化?需要我們這樣:面向接口編程。

    回顧一下:我們在設計中實現類依賴了具體的類,違反了依賴倒置原則。為了遵循依賴倒置原則,我們采用面向接口編程的方法,從而實現了面向對象的一條總的原則:封裝變化。


    看代碼:

    public interface AccountObserver
    {
        
    public void upDate(UserAccount userAccount);
    }

    public class Email implements AccountObserver
    {
        
    public void upDate(UserAccount userAccount)
        {
        }
    }

    public class Mobile
    {
        
    public void upDate(UserAccount userAccount)
        {
        }
    }

    public class BankAccount 
    {
        List 
    <AccountObserver> observer = new ArrayList<AccountObserver>;

        
    public void withDraw()
        {
             
    //
             for (AccountObserver ao : observer)
             {
                ao.upDate(userAccount)
              }
        }
        
        
    public void addOberver(AccountObserver accountObserver)
        {
              observer.add(accountObserver);
         }
    }

    UML圖:



    現在,BankAccount依賴于interface AccountObserver。Email和Mobile實現AccountObserver接口。通過遵循面向接口編程遵循了依賴倒置原則

    4.開閉原則

    終于修改好了,我們解決了訂閱者變化的問題。但如果發布者也傾向于變化呢?這就牽涉到面向對象里的另一個原則:開閉原則即:對擴展開放,對修改關閉。具體怎么做呢?通過抽象類,從抽象類繼承具體類。
    看最終的代碼(只寫幾個關鍵的方法,全貌可看最后的UML圖):

    訂閱:

    public interface AccountObserver
    {
        
    public void upDate(UserAccount userAccount);
    }

    public class Email implements AccountObserver
    {
        
    public void upDate(UserAccount userAccount)
        {
        }
    }

    public class Mobile implements AccountObserver
    {
        
    public void upDate(UserAccount userAccount)
        {
        }
    }


    發布:



    public abstract class Subject
    {
         List 
    <AccountObserver> observer = new ArrayList<AccountObserver>;

        
    protected void withDraw()
        {
             
    //
             notify();
             
        }
        
        
    protected void notify(UserAccount userAccount)
        {
             
    for (AccountObserver ao : observer)
             {
                ao.upDate(userAccount)
              }
         }
        
        
    protected void addOberver(AccountObserver accountObserver)
        {
              observer.add(accountObserver);
         }

          
    protected void deleteOberver(AccountObserver accountObserver)
        {
              observer.remove(accountObserver);
         }

    }

    public class BankAccount extends Subject
    {
        
    public void withDraw()
        {
             
    //
             for (AccountObserver ao : observer)
             {
                ao.upDate(userAccount)
              }
        }
        
    }



    看UML圖:




    5.觀察者模式概況




    這就是觀察者模式了,對比一下官方的UML圖,是不是一目了然了呢?
    稍作說明(這里的依賴都是指廣義的依賴):
    1.被觀察者ConcreteSubject繼承自Subject抽象類;
    2.Subject抽象類依賴于觀察者Observer抽象接口;
    3.觀察者ConcreteObserver實現Observer 接口;
    4.觀察者ConcreteObserver間接依賴于ConcreteSubject類。
    如果要增加具體的觀察者,只要再實現Obsever接口即可,而被觀察方不需要做任何修改。而如果需要修改被觀察者,只要從Subject抽象類繼承即可。

    posted on 2007-07-10 10:36 AAAAA 閱讀(322) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    <2007年7月>
    24252627282930
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    導航

    統計

    常用鏈接

    留言簿(1)

    隨筆檔案

    相冊

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲人成人无码网www电影首页| 免费黄色app网站| 久久久久国产成人精品亚洲午夜| 国产亚洲精品AAAA片APP| 国产伦一区二区三区免费| 老司机福利在线免费观看| 亚洲高清视频一视频二视频三| 日韩在线一区二区三区免费视频| 亚洲精品视频在线看| 国产免费人成视频在线播放播| 国精无码欧精品亚洲一区| 伊人久久免费视频| 亚洲va在线va天堂va手机| 女人张开腿等男人桶免费视频 | 春意影院午夜爽爽爽免费| 亚洲综合精品网站| 久久精品国产这里是免费| 亚洲日韩国产精品无码av| 人禽杂交18禁网站免费| 男男gvh肉在线观看免费| 久久精品国产亚洲一区二区| 四虎最新永久免费视频| 一本色道久久88亚洲精品综合| 免费观看日本污污ww网站一区| 九九热久久免费视频| 亚洲卡一卡2卡三卡4麻豆| 国产猛烈高潮尖叫视频免费| 花蝴蝶免费视频在线观看高清版| 亚洲欧洲精品久久| 国产乱弄免费视频| 日本免费一区二区久久人人澡| 亚洲一区二区三区国产精品无码| 免费人成在线观看播放国产| 青青草原1769久久免费播放| 最新亚洲卡一卡二卡三新区| 国产亚洲精品不卡在线| 成年女人视频网站免费m| 免费在线观影网站| 精品国产亚洲一区二区三区在线观看 | 免费观看日本污污ww网站一区| A片在线免费观看|