文章目录
- C++观察者模式代码实例一
- C++观察者模式代码实例二
C++观察者模式代码实例一
下面是一个简单的C++观察者模式的实现示例,这里仅给出核心代码框架,完整的工程应包含对应的头文件声明及必要的#include指令等。
// 观察者接口(Observer)
class IObserver {
public:
virtual ~IObserver() {}
virtual void update(const std::string& message) = 0; // 更新方法
};
// 主题接口(Subject)
class ISubject {
public:
virtual ~ISubject() {}
virtual void registerObserver(IObserver* observer) = 0; // 注册观察者
virtual void removeObserver(IObserver* observer) = 0; // 移除观察者
virtual void notifyObservers(const std::string& message) = 0; // 通知观察者
};
// 具体主题(ConcreteSubject)
class ConcreteSubject : public ISubject {
private:
std::vector<IObserver*> observers; // 存储观察者列表
public:
void registerObserver(IObserver* observer) override {
observers.push_back(observer);
}
void removeObserver(IObserver* observer) override {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notifyObservers(const std::string& message) override {
for (const auto& obs : observers) {
obs->update(message);
}
}
// 其他业务逻辑,当有状态改变时调用notifyObservers()
void changeState(const std::string& newState) {
// 假设这里有某种状态变更逻辑
std::string message = "状态已更新至:" + newState;
notifyObservers(message);
}
};
// 具体观察者(ConcreteObserver)
class ConcreteObserver : public IObserver {
public:
void update(const std::string& message) override {
std::cout << "Observer received message: " << message << std::endl;
// 在此处响应状态变更,执行观察者的相关操作
}
};
// 使用示例
int main() {
ConcreteSubject subject;
ConcreteObserver observer1;
ConcreteObserver observer2;
subject.registerObserver(&observer1);
subject.registerObserver(&observer2);
subject.changeState("New State"); // 当状态变化时,所有观察者都会被通知
return 0;
}
在这个例子中,ConcreteSubject
是具体的主题类,它可以添加和移除观察者,并在状态变化时通过调用 notifyObservers()
方法通知所有的观察者。ConcreteObserver
类则是实现了 IObserver
接口的观察者,当收到 update()
调用时,会执行相应的更新操作。主程序中创建了一个主题实例和两个观察者实例,并将观察者注册到主题上,当主题状态发生变化时,观察者接收到通知并作出反应。
在实际应用中,观察者模式通常用于设计事件驱动的系统,或者是当对象的状态变化需要自动通知其他对象时。以下是对上述代码实例的进一步阐述:
-
应用场景举例:假设你正在构建一个气象站系统,其中
ConcreteSubject
代表气象站,它记录并报告实时天气数据。ConcreteObserver
可以代表各种订阅气象信息的实体,如天气预报网站、农业自动化系统、交通管理系统等。 -
主体(Subject):当气象站检测到天气数据发生改变时,例如温度、湿度或风速变化,它会调用
notifyObservers()
方法,通知所有已注册的观察者。 -
观察者(Observer):每一个观察者在接收到
update()
调用时,会按照自己的需求处理这个更新消息。比如,天气预报网站会在页面上实时更新数据,农业自动化系统会据此调整灌溉计划,交通管理系统则可能据此发布道路预警信息。 -
灵活性:观察者模式提供了很好的灵活性,因为新增加的观察者只需实现
IObserver
接口,并通过主题的registerObserver()
方法注册自己,就可以开始接收更新通知,而不需要修改原有的主体或其它观察者。 -
松耦合:通过观察者模式,主题与观察者之间的耦合度较低,两者之间通过接口进行交互,这有助于简化系统的维护和扩展。
总之,通过这个简单的C++观察者模式实例,我们可以了解到如何构建一个具有动态通知机制的系统,使得当对象状态改变时,它的所有依赖对象都能得到及时的更新。在实际开发中,观察者模式广泛应用于GUI编程、事件处理、游戏开发、分布式系统等多种场景。
C++观察者模式代码实例二
另外,观察者模式还可以结合C++的一些现代特性进行优化,例如使用智能指针来管理观察者生命周期,以避免内存泄漏问题。下面是一个使用std::shared_ptr
改进后的观察者列表管理的例子:
#include <iostream>
#include <vector>
#include <memory>
// 观察者接口(Observer)
class IObserver {
public:
virtual ~IObserver() {}
virtual void update(const std::string& message) = 0;
};
// 主题接口(Subject)
class ISubject {
public:
virtual ~ISubject() {}
virtual void attach(std::shared_ptr<IObserver> observer) = 0;
virtual void detach(std::shared_ptr<IObserver> observer) = 0;
virtual void notifyObservers(const std::string& message) = 0;
};
// 具体主题(ConcreteSubject)
class ConcreteSubject : public ISubject {
private:
std::vector<std::shared_ptr<IObserver>> observers;
public:
void attach(std::shared_ptr<IObserver> observer) override {
observers.push_back(observer);
}
void detach(std::shared_ptr<IObserver> observer) override {
observers.erase(
std::remove(observers.begin(), observers.end(), observer),
observers.end()
);
}
void notifyObservers(const std::string& message) override {
for (const auto& obs : observers) {
obs->update(message);
}
}
// 其他业务逻辑...
};
// 具体观察者(ConcreteObserver)
class ConcreteObserver : public IObserver {
public:
void update(const std::string& message) override {
std::cout << "Observer received message: " << message << std::endl;
// 在此处响应状态变更,执行观察者的相关操作
}
};
// 使用示例
int main() {
ConcreteSubject subject;
auto observer1 = std::make_shared<ConcreteObserver>();
auto observer2 = std::make_shared<ConcreteObserver>();
subject.attach(observer1);
subject.attach(observer2);
subject.notifyObservers("New State"); // 当状态变化时,所有观察者都会被通知
return 0;
}
在这个改进版中,观察者列表现在存储的是指向观察者的智能指针,这样当观察者不再需要时,可以自动释放其占用的内存,有效防止了内存泄漏。同时,这也使得主题类与观察者之间的关系管理更加安全和可靠。
此外,观察者模式还可以与C++11/14/17的新特性结合起来,以更好地适应现代C++编程实践。例如:
- Lambda 表达式:在某些情况下,你可以使用lambda表达式作为临时观察者,这样就不必为一次性任务专门创建一个类。例如:
subject.attach([&](const std::string& message) {
std::cout << "Anonymous observer received message: " << message << std::endl;
});
subject.notifyObservers("New State");
std::function
和std::bind
:如果你需要传递已经存在的函数或成员函数作为观察者,可以使用std::function
和std::bind
来包装这些函数。例如,假设你有一个打印日志的全局函数或类成员函数:
void logMessage(const std::string& message) {
std::cout << "Log system received message: " << message << std::endl;
}
// 全局函数
subject.attach(logMessage);
// 成员函数,假设有一个Logger类
class Logger {
public:
void log(const std::string& message) {
std::cout << "Logger received message: " << message << std::endl;
}
};
Logger logger;
subject.attach(std::bind(&Logger::log, &logger, std::placeholders::_1));
通过这些现代C++特性的应用,观察者模式变得更加灵活,可以适应更多样化的场景和需求。同时,结合智能指针和其他内存管理工具,观察者模式的实现可以变得更安全、更易于维护。
除此之外,观察者模式还可以与C++17中的std::variant
和std::visit
配合使用,以处理不同类型的通知消息。例如,当主题拥有多种状态需要向观察者发送时,可以定义一个包含所有可能状态类型的std::variant
变量:
#include <variant>
enum class WeatherDataType { Temperature, Humidity, WindSpeed };
struct WeatherData {
WeatherDataType type;
double value;
};
class ConcreteSubject : public ISubject {
// ...
void notifyObservers(WeatherData data) override {
for (const auto& obs : observers) {
obs->update(data);
}
}
};
class AdvancedObserver : public IObserver {
public:
void update(const WeatherData& data) override {
std::visit(overloaded{
[&](const auto& value) {
if (data.type == WeatherDataType::Temperature)
handleTemperature(value);
// 处理其他类型...
},
}, data.value);
}
private:
void handleTemperature(double temp) {
std::cout << "Received temperature update: " << temp << std::endl;
}
// 处理其他数据类型的方法...
};
在此案例中,WeatherData
结构体包含了数据类型和对应的值,观察者可以根据type
字段判断所接收数据的具体类型,并通过std::visit
调用相应的方法进行处理。
综上所述,观察者模式与现代C++特性相结合,可以构建出更加灵活、类型安全且易于维护的系统,适用于各种复杂的事件驱动和状态变更通知场景。
python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)
50个开发必备的Python经典脚本(11-20)
50个开发必备的Python经典脚本(21-30)
50个开发必备的Python经典脚本(31-40)
50个开发必备的Python经典脚本(41-50)
————————————————
最后我们放松一下眼睛