Linux C++ 063-设计模式之观察者模式

Linux C++ 063-设计模式之观察者模式

本节关键字:Linux、C++、设计模式、观察者模式
相关库函数:

概念

观察者模式(有时又被称为发布/订阅模式)是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

实现方式

观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。

角色说明

观察者:(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。

被观察者:被观察对象发生了某种变化(如图中的Some Change),从容器中得到所有注册过的观察者,将变化通知观察者。

撤销观察:观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。

实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。

代码示例

// 定义一种一(被观察类)对多(观察类)的关系,让多个观察对象同时监听一个被观察对象,被观察对象状态发生变化时,会通知所有的观察对象,使他们能够更新自己的状态
// 观察者模式中存在两种角色:
//        观察者:内部包含被观察者对象,当被观察者对象的状态发生变化时,更新自己的状态(接收通知更新状态)
//        被观察者:内部包含了所有观察者对象,当状态发生变化时通知所有的观察者更新自己的状态(发送通知)
// 
// 被观察者基类(内部存放了所有的观察者对象,以便状态发生变化时,给观察者发通知)
class Observer;
class Subject
{
protected:
    list<Observer*> observers;
public:
    string action; // 被观察者对象的状态
    virtual void attach(Observer*) = 0;
    virtual void detach(Observer*) = 0;
    virtual void notify() = 0;
};
// 观察者基类 (内部实例化了被观察者的对象sub)
class Observer
{
protected:
    string name;
    Subject* sub;
public:
    Observer(string name, Subject* sub) {
        this->name = name;
        this->sub = sub;
    }
    virtual void update() = 0;
};
class StockObserver : public Observer
{
public:
    StockObserver(string name, Subject* sub) : Observer(name, sub)
    { }
    void update() {
        cout << name << "收到消息:" << sub->action << endl;
        if (sub->action == "梁所长来了!") {
            cout << "我马上关闭股票,装做很认真工作的样子!" << endl;
        }
    }
};
class NBAObserver :public Observer
{
public:
    NBAObserver(string name, Subject* sub) : Observer(name, sub)
    { }
    void update() {
        cout << name << "收到消息:" << sub->action << endl;
        if (sub->action == "梁所长来了!") {
            cout << "我马上关闭NBA,装做很认真工作的样子!" << endl;
        }
    }
};
class Secretary : public Subject
{
    void attach(Observer* observer) {
        observers.push_back(observer);
    }
    void detach(Observer* observer) {
        list<Observer*>::iterator iter = observers.begin();
        while (iter != observers.end()) {
            if ((*iter) == observer) {
                observers.erase(iter);
                return;
            }
            ++iter;
        }
    }
    void notify() {
        list<Observer*>::iterator iter = observers.begin();
        while (iter != observers.end()) {
            (*iter)->update();
            ++iter;
        }
    }
};
int main_Observer()
{
    Subject* dwq = new Secretary();
    Observer* xs = new NBAObserver("xiaoshuai", dwq);
    Observer* zy = new NBAObserver("zouyue", dwq);
    Observer* lm = new StockObserver("limin", dwq);

    dwq->attach(xs);
    dwq->attach(zy);
    dwq->attach(lm);

    dwq->action = "去吃饭了!";
    dwq->notify();
    cout << endl;

    dwq->action = "梁所长来了!";
    dwq->notify();
    return 0;
}
/* 运行结果:
xiaoshuai 收到消息:去吃饭了!
zouyue 收到消息:去吃饭了!
limin 收到消息:去吃饭了!

xiaoshuai 收到消息:梁所长来了!
我马上关闭NBA,装做很认真工作的样子!
zouyue 收到消息:梁所长来了!
我马上关闭NBA,装做很认真工作的样子!
limin 收到消息:梁所长来了!
我马上关闭股票,装做很认真工作的样子!
*/
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值