【设计模式】观察者

观察者模式,用于多个对象关注同一个对象的变化的情况。

王泽宾大牛写的文章比较生动,我只是用自己的理解实现了一个版本,而已。http://blog.csdn.net/wanghao72214/article/details/4017507


一,经典一点的实现,当然subject应该有个get_state的虚接口比较正宗,为了简单就先这样吧:

#include <string>
#include <iostream>
#include <vector>
#include <list>
using namespace std;

class Subject;

class Observer{
    public:
        Observer(Subject &sbj_obj)
        {
            sbj = &sbj_obj;
        }
        ~Observer(){}
        virtual int update() = 0;
        void set_name(string & strname){
            name = strname;
        }
        string get_name(){
            return name;
        }
        
    
        Subject * sbj;
        string name;
};

class Subject{
    public:
        Subject(){
            id = 0;
        }
        ~Subject(){}
        int attatch(Observer * obsv){
            obsvs.push_back(obsv);
        }
        int dettatch(Observer * obsv){
            obsvs.remove(obsv);
        }
        int notify(){
            id++;
            list<Observer *>::iterator iter = obsvs.begin();
            for (;iter != obsvs.end(); iter++){
                (*iter)->update();
            }
        }

        int get_id(){
            return id;
        }
    private:
        int id;
        list<Observer *> obsvs;
};

class Screen : public Observer{
    public:
        explicit Screen(Subject &sbj_obj):Observer(sbj_obj){}
        Screen(Subject &sbj_obj, string & strname):Observer(sbj_obj){
            set_name(strname);
        }
        ~Screen(){}
        int update(){
            cout<<get_name()<<" screan updated, sig:"<<sbj->get_id()<<"!"<<endl;
            return 0;
        }
};

class Speeker : public Observer{
    public:
        Speeker(Subject &sbj_obj):Observer(sbj_obj){}
        Speeker(Subject &sbj_obj, string & strname):Observer(sbj_obj){
            set_name(strname);
        }
        ~Speeker(){}
        int update(){
            cout<<get_name()<<" Speeker updated, sig:"<<sbj->get_id()<<"!"<<endl;
            return 0;
        }
};


int main(){
    Subject sbj;
    string scr1_name("scr1");
    string scr2_name("scr2");
    string spk1_name("spk1");
    Screen * scr1 = new Screen(sbj, scr1_name);
    Screen * scr2 = new Screen(sbj, scr2_name);
    Speeker * spk1 = new Speeker(sbj, spk1_name);

    sbj.attatch(scr1);
    sbj.attatch(scr2);
    sbj.attatch(spk1);

    sbj.notify();
    sbj.notify();

    return 0;
}

/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
二、带模板参数的观察者

我是觉得被观察者,只是需要给观察者发布一些消息而已。没必要subjet耦合到observer中。每个observer可以处理不同的subject发过来的消息才对。

这样需要增加一个消息类型参数。当然模板参数也只是编译时的参数,通过继承可以做到一些更灵活的实现。但动态加载这块,如果没有反射机制估计不太好实现。

#include <string>
#include <iostream>
#include <vector>
using namespace std;

template <class sig_type>
class Observer{
    public:
        Observer(){}
        ~Observer(){}
        virtual int update(sig_type &sig) = 0;
        void set_name(string & strname){
            name = strname;
        }
        string get_name(){
            return name;
        }
    private:
        string name;
};


class Counter{
    public:
        Counter(){
            count = 0;
        }
        ~Counter(){}
        int attatch(Observer<int> * obsv){
            observers.push_back(obsv);
            return 0;
        }
        int dettatch(Observer<int> * obsv){
            return 0;
            //observer.
        }
        int notify(){
            vector<Observer<int> *>::iterator iter = observers.begin();
            for ( ; iter != observers.end(); iter++){
                (*iter)->update(count);
            }
            return 0;
        }
        int add_count(){
            return ++count;
        }

        int get_count(){
            return count;
        }
    private:
        vector<Observer<int> *> observers;
        int count;
};

class Screen : public Observer<int>{
    public:
        explicit Screen(){}
        Screen(string & strname){
            set_name(strname);
        }
        ~Screen(){}
        int update(int &sig){
            cout<<get_name()<<" screan updated, sig:"<<sig<<"!"<<endl;
            return 0;
        }
};

class Speeker : public Observer<int>{
    public:
        Speeker(){}
        Speeker(string & strname){
            set_name(strname);
        }
        ~Speeker(){}
        int update(int &sig){
            cout<<get_name()<<" Speeker updated, sig:"<<sig<<"!"<<endl;
            return 0;
        }
};


int main(){
    Counter * counter = new Counter();
    string scr1_name("scr1");
    string scr2_name("scr2");
    string spk1_name("spk1");
    Screen * scr1 = new Screen(scr1_name);
    Screen * scr2 = new Screen(scr2_name);
    Speeker * spk1 = new Speeker(spk1_name);

    counter->attatch(scr1);
    counter->attatch(scr2);
    counter->attatch(spk1);

    counter->notify();
    counter->add_count();
    counter->notify();

    return 0;
}
这样实际上就不需要一个真正的subject对象了,而是定义一个消息类型即可。减少了一定的耦合。但是不知道有多少实用价值。

如果能做到动态加载不同的消息,我觉得比较理想。这样就从一个1:N关系,扩展到N:M关系,而且耦合也比较松。

后面再想想。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值