• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            設(shè)計模式之觀察者模式

            一、什么是觀察者模式

                 Observer模式也叫觀察者模式,是由GoF提出的23種軟件設(shè)計模式的一種。Observer模式是行為模式之一,它的作用是當一個對象的狀態(tài)發(fā)生變化時,能夠自動通知其他關(guān)聯(lián)對象,自動刷新對象狀態(tài)。

              觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開。舉個例子,用戶界面可以作為一個觀察者,業(yè)務(wù)數(shù)據(jù)是被觀察者,用戶界面觀察業(yè)務(wù)數(shù)據(jù)的變化,發(fā)現(xiàn)數(shù)據(jù)變化后,就顯示在界面上。面向?qū)ο笤O(shè)計的一個原則是:系統(tǒng)中的每個類將重點放在某一個功能上,而不是其他方面。一個對象只做一件事情,并且將他做好。觀察者模式在模塊之間劃定了清晰的界限,提高了應(yīng)用程序的可維護性和重用性。

             

              觀察者模式有很多實現(xiàn)方式,從根本上說,該模式必須包含兩個角色:觀察者和被觀察對象。在剛才的例子中,業(yè)務(wù)數(shù)據(jù)是被觀察對象,用戶界面是觀察者。觀察者和被觀察者之間存在“觀察”的邏輯關(guān)聯(lián),當被觀察者發(fā)生改變的時候,觀察者就會觀察到這樣的變化,并且做出相應(yīng)的響應(yīng)。如果在用戶界面、業(yè)務(wù)數(shù)據(jù)之間使用這樣的觀察過程,可以確保界面和數(shù)據(jù)之間劃清界限,假定應(yīng)用程序的需求發(fā)生變化,需要修改界面的表現(xiàn),只需要重新構(gòu)建一個用戶界面,業(yè)務(wù)數(shù)據(jù)不需要發(fā)生變化。

             

              “觀察”不是“直接調(diào)用”

              實現(xiàn)觀察者模式的時候要注意,觀察者和被觀察對象之間的互動關(guān)系不能體現(xiàn)成類之間的直接調(diào)用,否則就將使觀察者和被觀察對象之間緊密的耦合起來,從根本上違反面向?qū)ο蟮脑O(shè)計的原則。無論是觀察者“觀察”觀察對象,還是被觀察者將自己的改變“通知”觀察者,都不應(yīng)該直接調(diào)用。

             

              實現(xiàn)觀察者模式的形式

              實現(xiàn)觀察者模式有很多形式,比較直觀的一種是使用一種“注冊——通知——撤銷注冊”的形式。

             

               實現(xiàn)觀察者模式例子

                   下面是C++的實現(xiàn),在C++實現(xiàn)中,C++中沒有接口的概念,但是可以用抽象類類代替Java或C#中的接口,在C++中抽象類中從派生類中抽象出來的函數(shù)(方法),必須定義成純虛函數(shù),這樣在后面的使用中才可以通過基類的指針來訪問這些函數(shù),面向?qū)ο蟮恼Z言中有個特點,多態(tài)只能訪問兩者中共有的部分。

              1
              2#include "stdafx.h"
              3#include <string>
              4#include <vector>
              5#include<list>
              6#include<iostream>
              7using namespace std;
              8
              9class Observer;
             10class Subject
             11{
             12public:
             13    //注冊
             14     virtual void attach(Observer *o)=0;
             15     //撤銷
             16     virtual void dettach(Observer *o)=0;
             17     //發(fā)送消息,更新觀察者數(shù)據(jù)
             18     virtual void change()=0;
             19     //更新數(shù)據(jù)
             20     virtual void setWeather(string str)=0;
             21     //獲取數(shù)據(jù)
             22     virtual string getWeather()=0;
             23}
            ;
             24
             25class Observer
             26{
             27public:
             28    //獲得觀察者的名字,用于后面dettach撤銷操作
             29     virtual string getName()=0;
             30     //更新數(shù)據(jù),用于被觀察者調(diào)用
             31     virtual void update(Subject *s)=0;
             32}
            ;
             33
             34//被觀察者
             35class Earth: public Subject
             36{
             37private:
             38    //數(shù)據(jù)
             39     string weather;
             40     //存放觀察者的list,因為Observer是個抽象類,
             41     //所以不能聲明成 list<Observer >* l
             42     list<Observer* >* l;//指針 
             43public:
             44    //初始化存放觀察者的容器
             45     Earth()
             46     {
             47        l = new list<Observer*>;
             48     }
            ;
             49     //別忘了釋放資源
             50    ~Earth()
             51    {
             52        delete l;
             53    }
            ;
             54    //注冊觀察者
             55     void attach(Observer *o)
             56     {
             57        this->l->push_back(o);
             58     }
            ;
             59    
             60     //注銷觀察者
             61      void dettach(Observer *o)
             62     {
             63         for(list<Observer*>::iterator it=l->begin();it!=l->end();++it)
             64         {
             65             //通過string來進行查找,其他通過指針怎么判斷相等比較困難
             66             if( (*it)->getName() == o->getName())
             67             {
             68                 l->remove(*it);
             69                 break;
             70             }

             71         }

             72     }
            ;
             73
             74    //通知并更新觀察者
             75     void change()
             76     {
             77          for(list<Observer*>::iterator it=l->begin();it!=l->end();++it)
             78          {
             79            (*it)->update(this);
             80          }

             81     }
            ;
             82
             83     //更新數(shù)據(jù)
             84     void setWeather(string str)
             85     {
             86          this->weather=str;
             87          change();
             88     }
            ;
             89
             90     string getWeather()
             91     {
             92         return this->weather;
             93     }
            ;
             94
             95}
            ;
             96
             97class Satellite:public Observer
             98{
             99private:
            100     string name;
            101public:
            102     Satellite(string str)
            103     {
            104          name=str;
            105     }

            106     string getName()
            107     {
            108         return name;
            109     }
            ;
            110     //更新數(shù)據(jù)
            111     void update(Subject *s)
            112     {
            113         cout<<this->getName()+" "+s->getWeather()<<endl;
            114     }

            115}
            ;
            116
            117
            118
            119int _tmain(int argc, _TCHAR* argv[])
            120{
            121     Earth e;
            122     Satellite *s1 = new Satellite("風云一號");
            123     Satellite *s2 = new Satellite("風云二號");
            124     Satellite *s3 = new Satellite("風云三號");
            125     Satellite *s4 = new Satellite("風云四號");
            126     e.attach(s1);
            127     e.attach(s2);
            128     e.attach(s3);
            129     e.attach(s4);
            130     e.setWeather("fine");
            131     e.setWeather("rain");
            132     //注銷s3
            133     e.dettach(s3);
            134     e.setWeather("fine");
            135     e.setWeather("rain");
            136
            137
            138    return 0;
            139}

            140
            141

            以上文字參照http://blog.csdn.net/preciousboy/article/details/6230467,對其代碼進行修改在vs2008中編譯調(diào)試通過。
            結(jié)果運行為:


            這里要注意的幾個問題是?
            1.被觀察者怎么去通知觀察者數(shù)據(jù)已經(jīng)更新?--本例子中是通過void change()函數(shù)來實現(xiàn)的;
            2.在此模式中你可以從被觀察者處push或者pull數(shù)據(jù),我們認為push的方式是正確的。
            3.觀察者模式定義了一對多的關(guān)系
            4.有多個觀察者時不依賴于特定的通知次序。
            5.java的MVC模式就采用此模式實現(xiàn)。

            posted on 2012-05-01 11:47 sheng 閱讀(649) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            導(dǎo)航

            <2012年4月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            統(tǒng)計

            常用鏈接

            留言簿(1)

            隨筆檔案

            收藏夾

            同行

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久精品亚洲精品国产欧美| 久久久久亚洲精品天堂久久久久久| 亚洲国产精品综合久久网络| 久久精品国产欧美日韩99热| 久久精品国产久精国产果冻传媒 | 久久久久这里只有精品| 伊人情人综合成人久久网小说| 77777亚洲午夜久久多人| 99久久精品国产一区二区| 久久综合九色欧美综合狠狠 | 性做久久久久久久| 国产亚洲婷婷香蕉久久精品| 久久精品国产国产精品四凭| 无码人妻精品一区二区三区久久久 | 狠狠久久综合伊人不卡| 99精品国产综合久久久久五月天| 麻豆精品久久精品色综合| 久久久久亚洲AV无码专区首JN| 国产精品无码久久综合| 7777精品伊人久久久大香线蕉 | 97久久久久人妻精品专区| 亚洲国产成人久久一区WWW| 国产精品久久自在自线观看| 亚洲欧美伊人久久综合一区二区| 久久久久久久综合日本| 欧美久久精品一级c片片| 人妻无码中文久久久久专区| 久久人人青草97香蕉| 久久国产福利免费| 99久久精品免费国产大片| 7国产欧美日韩综合天堂中文久久久久| 亚洲精品乱码久久久久久久久久久久 | 欧美精品国产综合久久| 思思久久99热免费精品6| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 亚洲成人精品久久| 高清免费久久午夜精品| 成人国内精品久久久久一区| 欧美午夜精品久久久久免费视| 久久综合久久美利坚合众国| 久久精品aⅴ无码中文字字幕不卡|