• <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)斷開(注冊自動(dòng)取消),當(dāng)然,這也是實(shí)現(xiàn)該模式的重點(diǎn)。
              2)考慮了以下因素:一個(gè)Subject是否允許多個(gè)Observer觀察?一個(gè)Observer是否允許同時(shí)觀察多個(gè)Subject? 由此可分為一對一,一對多,多對多,一般的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 閱讀(2228) 評論(4)  編輯 收藏 引用

            評論

            # 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ù)  更多評論   

            # 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ù)  更多評論   

            # 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í),你的程序一樣會崩潰。因?yàn)樵谘h(huán)中的Observer 中的std::set<ISubject*> m_subjects;
            已經(jīng)發(fā)生了變化,而notify()里面的update循環(huán)仍然在繼續(xù)。。。  回復(fù)  更多評論   

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

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


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


            導(dǎo)航

            <2008年4月>
            303112345
            6789101112
            13141516171819
            20212223242526
            27282930123
            45678910

            統(tǒng)計(jì)

            常用鏈接

            留言簿(18)

            隨筆分類

            隨筆檔案

            服務(wù)器編程

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久国产精品无码HDAV| 久久精品国产亚洲7777| 7777久久亚洲中文字幕| 国产成人久久精品激情| 久久精品国产精品亚洲人人| 三级三级久久三级久久| 欧美精品一区二区精品久久| 久久久精品久久久久影院| 欧美一区二区精品久久| 久久综合给合综合久久| 国产精品久久久久无码av| 久久久这里有精品| 国产免费久久精品99久久| 色欲久久久天天天综合网| 色悠久久久久久久综合网| AV无码久久久久不卡蜜桃| 国产aⅴ激情无码久久| 久久久久久无码国产精品中文字幕 | 久久人与动人物a级毛片| 伊人色综合久久| 久久久久亚洲av无码专区导航| 久久99久久成人免费播放| 精品无码久久久久国产| 午夜精品久久久久久久久| 久久亚洲精品无码aⅴ大香 | 久久精品国产亚洲AV香蕉| 欧美亚洲国产精品久久| 久久久久亚洲精品男人的天堂| 久久国产精品久久久| 国产成人久久精品一区二区三区| 无码人妻精品一区二区三区久久| 九九精品久久久久久噜噜| 一级A毛片免费观看久久精品| 久久精品国产一区二区三区不卡| 国产精品99久久久久久宅男| 日本久久久久久中文字幕| 久久国产精品久久久| 国产激情久久久久影院| 久久福利片| 要久久爱在线免费观看| 久久久久久国产精品美女|