第二章 观察者模式

来源:互联网 发布:pcb 合拼算法 编辑:程序博客网 时间:2024/06/08 03:22

定义

观察者模式定义了对象之间一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

设计原则

为了交互对象之间的松耦合设计而努力。松耦合的设计之所以能让我们建立有弹性的OO系统,能够应付变化,是因为对象之间的互相依赖降到了最低。

代码实现

需求

有一个天气采集器,能够采集温度、湿度和气压,实现一个主题系统,该系统能够接受多个app的订阅,在采集器信息改变时,系统会获取到新的信息,并通知订阅的app,app则会将新数据展示出来。

分析

主题系统虽然可以在类的属性中添加每一个订阅者,但是这是在编译期决定的,没法在运行期动态添加订阅者,每当新添加或者删除一个订阅者的时候都需要改动类的代码并重新编译,这样不具备弹性,如果能将订阅者的添和删除放到运行期来做,这样就不需要改动类的代码,对象依赖就降低了。

// Subject.h#pragma once#include <iostream>#include <memory>#include <vector>#include <algorithm>#define CLASS_MEMBER_VAR(type, name)                                           \    public:                                                                    \        void set_##name(type name) { name##_ = name; }                         \        type name() const { return name##_; }                                  \    protected:                                                                 \        type name##_;class Subject;class Observer;typedef std::shared_ptr<Subject> SubjectPtr;typedef std::shared_ptr<Observer> ObserverPtr;class Subject {public:    typedef std::vector<ObserverPtr> ObserverList;    Subject();    void registerObserver(ObserverPtr o) {         observers_.push_back(o);        printf("Subject: register observer:%p done.\n", o.get());    }    void removeObserver(ObserverPtr o) {        auto pos = std::find_if(observers_.begin(), observers_.end(), [o](ObserverPtr ptr) {            return ptr.get() == o.get();        });        if (pos != observers_.end()) {            observers_.erase(pos);            printf("Subject: remove observer:%p done.\n", o.get());        }    }    void notifyObservers();private:    ObserverList observers_;    CLASS_MEMBER_VAR(double, temperature);    CLASS_MEMBER_VAR(double, pressure);    CLASS_MEMBER_VAR(double, humidity);};
// Subject.cpp#include "Subject.h"#include "Observer.h"Subject::Subject()  : temperature_(1.23),    pressure_(4.56),    humidity_(7.89){}void Subject::notifyObservers() { // observer will pull data    for (auto& o : observers_) {        o->update();    }}
// Observer.h#pragma once#include <memory>#include <vector>#include <iostream>class Subject;class Observer;typedef std::shared_ptr<Subject> SubjectPtr;typedef std::shared_ptr<Observer> ObserverPtr;class Observer : public std::enable_shared_from_this<Observer> {public:    Observer(SubjectPtr subject);    virtual ~Observer() { }    virtual void update() = 0;    virtual void display() = 0;protected:    SubjectPtr subject_;};class Observer1 : public Observer {public:    Observer1(SubjectPtr subject);    void update() override;    void display() override;};class Observer2 : public Observer {public:    Observer2(SubjectPtr subject);    void update() override;    void display() override;};
// Observer.cpp#include "Observer.h"#include "Subject.h"Observer::Observer(SubjectPtr subject)  : subject_(subject){}Observer1::Observer1(SubjectPtr subject)  : Observer(subject){}void Observer1::update() {    printf("Observer1: received update from Subject.\n");    display();}void Observer1::display() {    printf("Observer1: pull data from Subject and display it.\n");    printf("\ttemperature: %lf\n", subject_->temperature());    printf("\thumidity: %lf\n", subject_->humidity());    printf("\tpressure: %lf\n", subject_->pressure());}Observer2::Observer2(SubjectPtr subject)  : Observer(subject){}void Observer2::update() {    printf("Observer2: received update from Subject.\n");    display();}void Observer2::display() {    printf("Observer2: pull data from Subject and display it.\n");    printf("Observer2(%p): remove from Subject.\n", this);    subject_->removeObserver(shared_from_this());}
// main.cpp#include "Subject.h"#include "Observer.h"using namespace std;int main(int argc, char** argv) {    SubjectPtr subject(new Subject());    ObserverPtr observer1(new Observer1(subject));    subject->registerObserver(observer1);    ObserverPtr observer2(new Observer2(subject));    subject->registerObserver(observer2);    subject->notifyObservers();    return 0;}
// Makefileall: observerobserver: main.cpp Observer.cpp Subject.cpp    c++ -g -std=c++11 -o $@ $^clean:    -rm -rf observer

不得不说,即便是C++11,在使用上依旧缺陷重重,本章在代码实现过程中碰到几个特别烦人的问题:
1、先声明再使用的规定极大地限制了代码的简洁性,违反了DRY原则,降低了封装性,弊大于利。对象互相调用对方的方法时,比如A调用B的方法fb(), B调用A的方法fa(),代码若在同一个文件内实现会很蹩脚。
2、构造函数内能做的事情极其有限。我想在Observer类的构造函数里面将该对象注册到Subject对象之中去,由于需要传递当前对象的shared_ptr,但是在构造函数里无法获得当前对象的shared_ptr,即便让该类继承enable_shared_from_this也不行,为此,不得不将初始化工作分成两步,在构造函数之外进行注册,这样极大地降低了代码的封装性。另外在使用shared_from_this()的时候必须要确保对象在堆上且引用计数不为0,否则会抛出异常。
以上问题在Java里面根本不存在!

原创粉丝点击