今天来准备浅浅的过一下观察者模式,观察者模式也叫作:发布者订阅者模式。该模式的特点是多个对象依赖一个对象,为一对多依赖关系,每当一个对象改变时,所有依赖它的对象都会得到通知并自动更新,该模式主要维护主题类和观察者类。使用观察者模式的典型应用场景为:系统事件通知、电商订阅、消息订阅、状态更新、动态图形,这些场景多为事件驱动系统。它的实现同样以C++的继承、封装、多台为地基。
目录
一、观察者模式简单介绍
二、简单的观察者模式
三、多线程观察者模式
四、线程池实现
五、简单的电商订阅系统
代码链接:
Thomas_Lbw / Cpp_Design_Patterns · GitCode
一、观察者模式简单介绍
观察者模式具体由以下几个模块组成:
1. 抽象主题(Subject):它将所有观察者对象的引用保存在同一个集合里,每个主题都有任意数量的观察者。抽象主题提供外部接口用于增加、删除对象。
class Subject {
public:
virtual void RegisterObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
virtual void NotifyObservers() = 0;
};
2. 具体主题(Concrete Subject):将有关状态存入具体观察者对象。具体主题的内部状态改变,给所有登记过的观察者发出通知。
// 具体主题类
class ConcreteSubject : public Subject {
public:
void RegisterObserver(Observer* observer) override {
observers_.push_back(observer);
}
void RemoveObserver(Observer* observer) override {
auto it = std::find(observers_.begin(), observers_.end(), observer);
if (it != observers_.end()) {
observers_.erase(it);
}
}
void NotifyObservers() override {
for (Observer* observer : observers_) {
observer->Update(value_);
}
}
void SetValue(int value) {
value_ = value;
NotifyObservers();
}
private:
std::vector<Observer*> observers_;
int value_;
};
3. 抽象观察者(Observer):为目标发生改变时需获得通知的对象定义一个更新接口。
// 抽象观察者类
class Observer {
public:
virtual void Update(int value) = 0;
};
4. 具体观察者(Concrete Observer):存储有关状态,这些状态跟目标状态保持一致。提供Observer的更新接口以使自身状态与目标状态保持一致。
class ConcreteObserver : public Observer {
public:
ConcreteObserver(int id) : id_(id) {}
void Update(int value) override {
std::cout << "Observer " << id_ << " received update: " << value << std::endl;
}
private:
int id_;
};
小结:观察者模式定义了一种一对多的关系,即一个主题对象可以有多个观察者,当主题对象状态发生改变时,会通知所有的观察者。观察者模式基于对象间的松散耦合,通过解耦对象之间的依赖关系,从而使得系统更加灵活,易于维护和扩展。
二、简单的观察者模式
代码示例:
#include <iostream>
#include <vector>
#include <algorithm>
// 抽象观察者类
class Observer {
public:
virtual void Update(int value) = 0;
};
// 具体观察者类
class ConcreteObserver : public Observer {
public:
ConcreteObserver(int id) : id_(id) {}
void Update(int value) override {
std::cout << "Observer " << id_ << " received update: " << value << std::endl;
}
private:
int id_;
};
// 抽象主题类
class Subject {
public:
virtual void RegisterObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
virtual void NotifyObservers() = 0;
};
// 具体主题类
class ConcreteSubject : public Subject {
public:
void RegisterObserver(Observer* observer) override {
observers_.push_back(observer);
}
void RemoveObserver(Observer* observer) override {
auto it = std::find(observers_.begin(), observers_.end(), observer);
if (it != observers_.end()) {
observers_.erase(it);
}
}
void NotifyObservers() override {
for (Observer* observer : observers_) {
observer->Update(value_);
}
}
void SetValue(int value) {
value_ = value;
NotifyObservers();
}
private:
std::vector<Observer*> observers_;
int value_;
};
int main() {
ConcreteSubject subject;
ConcreteObserver observer1(1);
ConcreteObserver observer2(2);
subject.RegisterObserver(&observer1);
subject.RegisterObserver(&observer2);
subject.SetValue(123);
subject.RemoveObserver(&observer1);
subject.SetValue(456);
return 0;
}
执行结果:
1. 抽象观察者类 Observer:提供了一个虚拟函数 Update,用于更新观察者对象的状态。
2. 具体观察者类 ConcreteObserver:继承自 Observer,并实现了 Update 函数。在该类中,通过输出语句来模拟观察者更新自身状态的过程。
3. 抽象主题类 Subject:提供了注册、删除和通知观察者的接口。
4. 具体主题类 ConcreteSubject:继承自 Subject,并实现了注册、删除和通知观察者的接口。在该类中,通过维护一个存储观察者的容器来管理观察者的注册、删除和通知。
5. main 函数:创建了一个 ConcreteSubject 和两个 ConcreteObserver 对象,通过注册、删除和通知等操作来演示观察者模式的基本逻辑。
类图:
三、多线程观察者模式
为保护对象安全,可以采用多线程来实现:
#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
#include <mutex>
class Observer {
public:
virtual void Update(int value) = 0;
};
class ConcreteObserver : public Observer {
public:
ConcreteObserver(int id) : id_(id) {}
void Update(int value) override {
std::cout << "Observer " << id_ << " received update: " << value << std::endl;
}
private:
int id_;
};
class Subject {
public:
virtual void RegisterObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
virtual void NotifyObservers() = 0;
};
class ConcreteSubject : public Subject {
public:
void RegisterObserver(Observer* observer) override {
std::unique_lock<std::mutex> lock(observers_mutex_);
observers_.push_back(observer);
}
void RemoveObserver(Observer* observer) override {
std::unique_lock<std::mutex> lock(observers_mutex_);
auto it = std::find(observers_.begin(), observers_.end(), observer);
if (it != observers_.end()) {
observers_.erase(it);
}
}
void NotifyObservers() override {
std::unique_lock<std::mutex> lock(observers_mutex_);
for (Observer* observer : observers_) {
std::thread t(&Observer::Update, observer, value_);
t.detach();
}
}
void SetValue(int value) {
value_ = value;
NotifyObservers();
}
private:
std::vector<Observer*> observers_;
std::mutex observers_mutex_;
int value_;
};
int main() {
ConcreteSubject subject;
ConcreteObserver observer1(1);
ConcreteObserver observer2(2);
subject.RegisterObserver(&observer1);
subject.RegisterObserver(&observer2);
subject.SetValue(123);
subject.RemoveObserver(&observer1);
subject.SetValue(456);
return 0;
}
在方法RegisterObserver和RemoveObserver中使用了unique_lock来获取互斥锁,保护观察者列表线程安全。
四、线程池实现
学以致用C++设计模式 之 “观察者模式” - 腾讯云开发者社区-腾讯云
五、简单的电商订阅系统
#include <iostream>
#include <string>
#include <vector>
#include <functional>
class Observable;
class Observer {
public:
virtual ~Observer() {}
virtual void Update(const Observable& obs) = 0;
};
class Observable {
public:
void RegisterObserver(Observer* observer) {
observers_.push_back(observer);
}
void NotifyObservers() const {
for (const auto& observer : observers_) {
observer->Update(*this);
}
}
private:
std::vector<Observer*> observers_;
};
class Product : public Observable {
public:
Product(const std::string& name, double price)
: name_(name), price_(price) {}
void SetPrice(double price) {
price_ = price;
NotifyObservers();
}
std::string GetName() const { return name_; }
double GetPrice() const { return price_; }
private:
std::string name_;
double price_;
};
class Subscriber : public Observer {
public:
Subscriber(const std::string& name, Product& product)
: name_(name), product_(product) {
product_.RegisterObserver(this);
}
void Update(const Observable& obs) override {
std::cout << name_ << ": Product " << product_.GetName()
<< " price changed to " << product_.GetPrice() << std::endl;
}
private:
std::string name_;
Product& product_;
};
int main() {
Product laptop("Laptop", 1000.0);
Subscriber subscriber1("Subscriber 1", laptop);
Subscriber subscriber2("Subscriber 2", laptop);
laptop.SetPrice(900.0);
laptop.SetPrice(950.0);
return 0;
}