• <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>

            eXile 的專欄

            觀察者 (Subject/Observer) 模式實(shí)現(xiàn)

              以前我曾經(jīng)實(shí)現(xiàn)過觀察者模式(signal / slot )。有位朋友不以為然,也把他的實(shí)現(xiàn)發(fā)給我。這是用純OO的方式實(shí)現(xiàn)的,沒有使用模板,不依賴于其它庫。應(yīng)該是仿Java或C#接口。設(shè)計(jì)得不錯(cuò),具有以下特點(diǎn):
              1)當(dāng)Subject或Observer 銷毀時(shí),連接自動(dòng)斷開(注冊(cè)自動(dòng)取消),當(dāng)然,這也是實(shí)現(xiàn)該模式的重點(diǎn)。
              2)考慮了以下因素:一個(gè)Subject是否允許多個(gè)Observer觀察?一個(gè)Observer是否允許同時(shí)觀察多個(gè)Subject? 由此可分為一對(duì)一,一對(duì)多,多對(duì)多,一般的GUI庫中都是后兩種情況,但自己寫的程序中卻第一種情況居多。所以他出于效率,設(shè)計(jì)了SimpleSubject和SimpleObserver。
              
              不足之處如下:
              1)Observer::update()只能帶無類型的參數(shù)(好象也沒有更好的辦法)。
              2)由于C++中沒有匿名類,所以使用起來并沒有Java中方便。于是我又添加了一個(gè)ObserverAdapter。

              使用舉例:


            class A : 
            public Subject
            {
                    int value;
            public:
               void setValue(
            int v)
               {
                   value 
            = v;
                   notify(
            &value);
               }       
            };

            class B : 
            public Observer
            {
            public:
               void update(void
            * arg)
               {
                   printf(
            "A changed:%d"*(int*)arg);
               }       
            };

            void f(A
            * a, B* b)
            {
                a
            ->connect(b);
                a
            ->setValue(1); 
            }

            使用ObserverAdapter ,則變成了以下情況:
            class B 
            {
               ObserverAdapter
            <B> observerOfA;
            public:
               B(A
            * a) : observerOfA(this, &B::valueChanged)
               {
                   a
            ->connect(&observerOfA);
               }

               void valueChanged(void
            * arg)
               {
                   printf(
            "A changed:%d"*(int*)arg);
               }       
            };


              代碼分為兩個(gè)文件:IObserver.h 和 Observer.h,就貼在下面吧:

            IObserver.h  : 接口定義

            #pragma once

            class ISubject;

            class IObserver 
            {
            public:
                IObserver()  {}
                virtual ~IObserver() {};

                virtual void update(void
            *= 0;
                
            protected:
                virtual void addSubject(ISubject
            * ) = 0;
                virtual void removeSubject(ISubject
            * ) = 0

                friend class ISubject;
                
            private:
                IObserver(IObserver 
            const&);
                IObserver
            & operator= (IObserver const&);
            };

            class ISubject 
            {
            public:
                ISubject() {}
                virtual ~ISubject() {};

                virtual void connect(IObserver
            *= 0;
                virtual void disconnect(IObserver
            *= 0;
                virtual bool isConnected(IObserver
            *const= 0;
                virtual void notify(void
            *= 0;

            protected:
                void addObserver(IObserver
            * observer);
                void removeObserver(IObserver
            * observer);

            private:
                ISubject(ISubject 
            const&);
                ISubject
            & operator= (ISubject const&);
            };


            Observer.h  : 具體實(shí)現(xiàn)

            #pragma once

            #include 
            <cassert>
            #include 
            <set>

            #include 
            "IObserver.h"

            //-------------------------------------------------------------------

            inline void ISubject::addObserver(IObserver
            * observer)
            {
                observer
            ->addSubject(this);
            }

            inline void ISubject::removeObserver(IObserver
            * observer)
            {
                observer
            ->removeSubject(this);
            }

            //-------------------------------------------------------------------

            class SimpleSubject : 
            public ISubject
            {
            public:
                SimpleSubject() : m_observer(
            0)
                {
                }
                
                ~SimpleSubject()
                {
                    
            if (m_observer) removeObserver(m_observer);
                }
                
                virtual void connect(IObserver
            * observer)
                {
                    assert(observer);
                    
            if (m_observer)
                        removeObserver(m_observer);
                    addObserver(observer);
                    m_observer 
            = observer;
                }
                
                virtual void disconnect(IObserver
            * observer)
                {
                    assert(observer 
            && observer == m_observer);
                    removeObserver(m_observer);
                    m_observer 
            = 0;
                }

                virtual bool isConnected(IObserver
            * observer) const
                {
                    return observer 
            == m_observer;
                }

                virtual void notify(void
            * arg)
                {
                    
            if (m_observer) m_observer->update(arg);
                }
                
            private:
                IObserver
            *  m_observer;
                
            };

            //-------------------------------------------------------------------

            class Subject : 
            public ISubject
            {
            public:
                Subject() : m_observers()
                {
                }
                
                ~Subject()
                {
                    std::
            set<IObserver*>::iterator
                        it 
            = m_observers.begin(),
                        e  
            = m_observers.end();
                    
            for (; it != e; ++it)
                    {
                        removeObserver(
            *it);
                    }
                }
                
                virtual void connect(IObserver
            * observer)
                {
                    assert(observer);
                    addObserver(observer);
                    m_observers.insert(observer);
                }
                
                virtual void disconnect(IObserver
            * observer)
                {
                    assert(observer);
                    removeObserver(observer);
                    m_observers.erase(observer);
                }

                virtual bool isConnected(IObserver
            * observer) const
                {
                    return m_observers.find(observer) !
            = m_observers.end();
                }

                virtual void notify(void
            * arg)
                {
                    std::
            set<IObserver*>::iterator
                        it 
            = m_observers.begin(),
                        e  
            = m_observers.end();
                    
            while (it != e)
                    {
                        (
            *it++)->update(arg); // observer can be disconnected in update()
                    }
                }
                
            private:
                std::
            set<IObserver*>  m_observers;
                
            };

            //-------------------------------------------------------------------

            class SimpleObserver  : 
            public IObserver
            {
            public:
                SimpleObserver() : m_subject(
            0)
                {
                }
                
                ~SimpleObserver()
                {
                    
            if (m_subject) m_subject->disconnect(this);
                }

                ISubject
            * getSubject() const
                {
                    return m_subject;
                }
                
            private:
                virtual void addSubject(ISubject
            * subject)
                {
                    
            if (m_subject) m_subject->disconnect(this);
                    m_subject 
            = subject;
                }

                virtual void removeSubject(ISubject
            * subject)
                {
                    assert(subject 
            == m_subject);
                    m_subject 
            = 0;
                }

            private:
                ISubject
            *   m_subject;
            };


            //-------------------------------------------------------------------

            class Observer : 
            public IObserver
            {
            public:
                Observer() : m_subjects()
                {
                }
                
                ~Observer()
                {
                    std::
            set<ISubject*>::iterator
                        it 
            = m_subjects.begin(),
                        e  
            = m_subjects.end();
                    
            while (it != e)
                    {
                        (
            *it++)->disconnect(this);
                    }
                }
                
            private:
                virtual void addSubject(ISubject
            * subject)
                {
                    assert(subject);
                    m_subjects.insert(subject);
                }
                
                virtual void removeSubject(ISubject
            * subject)
                {
                    assert(subject);
                    m_subjects.erase(subject);
                }

            private:
                std::
            set<ISubject*>   m_subjects;
            };

            //-------------------------------------------------------------------

            template 
            <class T, class Base = SimpleObserver>
            class ObserverAdapter  : 
            public Base
            {
            public:
                ObserverAdapter(T
            * t, void (T::*f)(void*))
                 : m_obj(t), m_func(f)
                {
                }

                virtual void update(void
            * arg)
                {
                    (m_obj
            ->*m_func)(arg);
                }
                
            private:
                T
            *  m_obj;
                void (T::
            *m_func)(void*);
            };

            //-------------------------------------------------------------------

            posted on 2007-09-16 11:30 eXile 閱讀(2219) 評(píng)論(4)  編輯 收藏 引用

            評(píng)論

            # re: 觀察者 (Subject/Observer) 模式實(shí)現(xiàn) 2007-09-17 23:40 eXile

            發(fā)現(xiàn)這種設(shè)計(jì)還有兩個(gè)優(yōu)點(diǎn):
            (1)observer雖然用于解藕很不錯(cuò),但是在C++中,最大的問題是容易出現(xiàn)懸掛指針,而且出現(xiàn)后不易調(diào)試。這個(gè)實(shí)現(xiàn)在這一方面做得很不錯(cuò),可以最大限度的防止這類問題的出現(xiàn)。
            (2)由于定義了抽象接口,很容易擴(kuò)充為線程安全的實(shí)現(xiàn)  回復(fù)  更多評(píng)論   

            # re: 觀察者 (Subject/Observer) 模式實(shí)現(xiàn) 2007-09-17 23:48 eXile

            至于Observer::update(void*)可以利用ObserverAdapter實(shí)現(xiàn)接口強(qiáng)制,再利用 std::tr1::tuple 之類的來彌補(bǔ)類型信息的不足  回復(fù)  更多評(píng)論   

            # re: 觀察者 (Subject/Observer) 模式實(shí)現(xiàn) 2007-09-26 13:28 xiehp@sohu.com

            不知道你的注釋
            // observer can be disconnected in update()
            依據(jù)從何而來
            我覺得如果concrete observer 重載update()并在里面調(diào)用了disconnected時(shí),你的程序一樣會(huì)崩潰。因?yàn)樵谘h(huán)中的Observer 中的std::set<ISubject*> m_subjects;
            已經(jīng)發(fā)生了變化,而notify()里面的update循環(huán)仍然在繼續(xù)。。。  回復(fù)  更多評(píng)論   

            # re: 觀察者 (Subject/Observer) 模式實(shí)現(xiàn)[未登錄] 2007-09-26 14:33 eXile

            @xiehp@sohu.com
            這就是 it++ 和 ++it 的區(qū)別  回復(fù)  更多評(píng)論   


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


            導(dǎo)航

            <2007年9月>
            2627282930311
            2345678
            9101112131415
            16171819202122
            23242526272829
            30123456

            統(tǒng)計(jì)

            常用鏈接

            留言簿(18)

            隨筆分類

            隨筆檔案

            服務(wù)器編程

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            亚洲人成电影网站久久| 国产精品成人久久久久三级午夜电影 | 久久婷婷五月综合色99啪ak| 亚洲欧美成人久久综合中文网| 无码超乳爆乳中文字幕久久| 蜜桃麻豆www久久| 亚洲精品无码久久久久sm| 久久久精品一区二区三区| 国产精品久久久久久久人人看| 韩国无遮挡三级久久| 区久久AAA片69亚洲| 久久精品无码一区二区app| 久久综合亚洲欧美成人| 亚洲精品tv久久久久| 久久精品嫩草影院| 久久久无码人妻精品无码| 久久人妻少妇嫩草AV无码蜜桃| 996久久国产精品线观看| 久久WWW免费人成一看片| 热RE99久久精品国产66热| 久久国产乱子伦精品免费强| 亚洲午夜久久久久妓女影院| 欧美精品福利视频一区二区三区久久久精品 | 一本一道久久a久久精品综合 | 久久婷婷人人澡人人| 国产成人综合久久久久久| 久久免费精品一区二区| 99久久超碰中文字幕伊人| 亚洲国产精品无码久久一线 | 久久精品aⅴ无码中文字字幕不卡| 久久精品国产一区| 韩国无遮挡三级久久| 成人国内精品久久久久影院| 人妻久久久一区二区三区| 天天躁日日躁狠狠久久| 无码日韩人妻精品久久蜜桃 | 久久国产热这里只有精品| 久久久久香蕉视频| 亚洲欧美国产精品专区久久| 色综合久久夜色精品国产| 波多野结衣久久一区二区 |