设计模式-观察者模式

设计模式-观察者模式是一种订阅方式的设计模式,类似于互联网上的订阅方式,但是缺少了通信过程和中间件的参与。

动机:

在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密, 将使软件不能很好地抵御变化。

使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合

案例:

案例:文件分割器,在界面上显示分割进度

C++中尽量不要多继承,因为会有很多问题。但是可以继承一个主基类,然后再继承多个接口,这样一般是没问题的

抽象:将“通知依赖”关系抽象为1个接口,比如案例中splitter就是被观察者,界面窗口(进度条)、控制台就是观察者

如何支持多个观察者:vector

要点总结:

使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。

目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。

观察者自己决定是否需要订阅通知,目标对象对此一无所知。

Observer模式是基于事件的UI框架中非常常用的设计模式,也是 MVC模式的一个重要组成部分。

https://github.com/zhtsmailbox/design-patterns-cpp/blob/master/docs/Observer.md

#include <iostream>
#include <vector>

class Subject;

/*
 * Observer
 * defines an updating interface for objects that should be notified
 * of changes in a subject
 */
class Observer
{
public:
  virtual ~Observer() {}
  
  virtual int getState() = 0;
  virtual void update( Subject *subject ) = 0;
  // ...
};

/*
 * Concrete Observer
 * stores state of interest to ConcreteObserver objects and
 * sends a notification to its observers when its state changes
 */
class ConcreteObserver : public Observer
{
public:
  ConcreteObserver( const int state ) :
    observer_state( state ) {}
  
  ~ConcreteObserver() {}
  
  int getState()
  {
    return observer_state;
  }
  
  void update( Subject *subject );
  // ...

private:
  int observer_state;
  // ...
};

/*
 * Subject
 * knows its observers and provides an interface for attaching
 * and detaching observers
 */
class Subject
{
public:
  virtual ~Subject() {}
  
  void attach( Observer *observer )
  {
    observers.push_back(observer);
  }
  
  void detach( const int index )
  {
    observers.erase( observers.begin() + index );
  }
  
  void notify()
  {
    for ( unsigned int i = 0; i < observers.size(); i++ )
    {
      observers.at( i )->update( this );
    }
  }
  
  virtual int getState() = 0;
  virtual void setState( const int s ) = 0;
  // ...

private:
  std::vector<Observer*> observers;
  // ...
};

/*
 * Concrete Subject
 * stores state that should stay consistent with the subject's
 */
class ConcreteSubject : public Subject
{
public:
  ~ConcreteSubject() {}
  
  int getState()
  {
    return subject_state;
  }
  
  void setState( const int s )
  {
    subject_state = s;
  }
  // ...
  
private:
  int subject_state;
  // ...
};

void ConcreteObserver::update( Subject *subject )
{
  observer_state = subject->getState();
  std::cout << "Observer state updated." << std::endl;
}


int main()
{
  ConcreteObserver observer1( 1 );
  ConcreteObserver observer2( 2 );
  
  std::cout << "Observer 1 state: " << observer1.getState() << std::endl;
  std::cout << "Observer 2 state: " << observer2.getState() << std::endl;
  
  Subject *subject = new ConcreteSubject();
  subject->attach( &observer1 );
  subject->attach( &observer2 );
  
  subject->setState( 10 );
  subject->notify();
  
  std::cout << "Observer 1 state: " << observer1.getState() << std::endl;
  std::cout << "Observer 2 state: " << observer2.getState() << std::endl;
  
  delete subject;
  return 0;
}

以上是课程相关内容,接下来我们要做一个小练习

题目:一个软件用于天气订阅,由一个天气信息分发者和多个天气信息订阅者组成,其中订阅者要注册,分发者要向所有的订阅者进行信息分发,每当天气信息发生改变的时候,都会向订阅者分发温度信息。

我们将天气信息分发者看作被观察者(Subject),订阅者看作观察者(Observer)

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

class Observer {
public:
    virtual void update(float temperature) = 0;
    virtual ~Observer() = default;
};

class WeatherSubscriber : public Observer {
    string name;
public:
    WeatherSubscriber(const string& n) : name(n) {}
    void update(float temperature) override {
        cout << name << " 收到天气更新:温度为 " << temperature << "°C\n";
    }
};

class WeatherPublisher {
    vector<Observer*> observers;
    float temperature;
public:
    void registerObserver(Observer* o) {
        observers.push_back(o);
    }

    void removeObserver(Observer* o) {
        observers.erase(remove(observers.begin(), observers.end(), o), observers.end());
    }

    void setTemperature(float t) {
        temperature = t;
        notifyObservers();
    }

    void notifyObservers() {
        cout << "\n天气更新:当前温度为 " << temperature << "°C,通知订阅者...\n";
        for (auto* o : observers) {
            o->update(temperature);
        }
    }
};

使用方式:

int main() {
    WeatherPublisher publisher;

    WeatherSubscriber a("小明"), b("小红");

    publisher.registerObserver(&a);
    publisher.registerObserver(&b);

    publisher.setTemperature(22.5);

    publisher.removeObserver(&b);

    publisher.setTemperature(28.0);

    return 0;
}

输出示例:

天气更新当前温度为 22.5°C通知订阅者...
小明 收到天气更新温度为 22.5°C
小红 收到天气更新温度为 22.5°C

天气更新当前温度为 28°C通知订阅者...
小明 收到天气更新温度为 28°C
          +----------------+
          |   Observer     |<----------------------+
          +----------------+                       |
          | +update(float) |                       |
          +----------------+                       |
|
                   |                               |
         +---------------------+          +------------------------+
         | WeatherSubscriber   |          |   WeatherPublisher     |
         +---------------------+          +------------------------+
         | -name: string       |          | -observers: list<Observer*> |
         +---------------------+          | -temperature: float     |
         | +update(float)      |          +------------------------+
         +---------------------+          | +registerObserver(o*)   |
                                          | +removeObserver(o*)     |
                                          | +setTemperature(float)  |
                                          | +notifyObservers()      |
                                          +------------------------+