代码还可以从以下几个方面进行改进,提升代码的健壮性、灵活性和性能:
1. 使用 std::weak_ptr
避免循环引用
在观察者模式中,如果 Subject
和 Observer
之间的关系过于复杂,且双方都使用 std::shared_ptr
彼此引用,可能会导致循环引用(也称为“循环依赖”),使得智能指针无法释放内存,导致内存泄漏。
改进措施:使用 std::weak_ptr
打破循环引用。std::weak_ptr
不增加引用计数,它只持有对象的弱引用。
在这个例子中,Subject
持有观察者的 std::weak_ptr
,而观察者依旧可以使用 std::shared_ptr
。
#include <iostream>
#include <vector>
#include <string>
#include <memory>
class Observer {
public:
virtual ~Observer() {}
virtual void update(const std::string& message_from_subject) = 0;
};
class Subject {
public:
virtual ~Subject() {}
virtual void attach(std::shared_ptr<Observer> observer) = 0;
virtual void detach(std::shared_ptr<Observer> observer) = 0;
virtual void notify() = 0;
};
class ConcreteSubject : public Subject {
private:
std::vector<std::weak_ptr<Observer>> observers; // 使用weak_ptr打破循环引用
std::string message;
public:
void attach(std::shared_ptr<Observer> observer) override {
observers.push_back(observer);
}
void detach(std::shared_ptr<Observer> observer) override {
observers.erase(
std::remove_if(observers.begin(), observers.end(),
[&observer](const std::weak_ptr<Observer>& o) {
return o.lock() == observer;
}),
observers.end());
}
void notify() override {
for (auto it = observers.begin(); it != observers.end();) {
if (auto observer = it->lock()) { // lock() 将 weak_ptr 转换为 shared_ptr
observer->update(message);
++it;
} else {
it = observers.erase(it); // 如果对象已被销毁,移除观察者
}
}
}
void createMessage(const std::string& message) {
this->message = message;
notify();
}
};
class ConcreteObserver : public Observer {
private:
std::string name;
std::string message_from_subject;
public:
ConcreteObserver(const std::string& name) : name(name) {}
void update(const std::string& message_from_subject) override {
this->message_from_subject = message_from_subject;
display();
}
void display() const {
std::cout << "Observer [" << name << "] received message: " << message_from_subject << std::endl;
}
};
int main() {
auto subject = std::make_shared<ConcreteSubject>();
auto observer1 = std::make_shared<ConcreteObserver>("Observer 1");
auto observer2 = std::make_shared<ConcreteObserver>("Observer 2");
auto observer3 = std::make_shared<ConcreteObserver>("Observer 3");
subject->attach(observer1);
subject->attach(observer2);
subject->attach(observer3);
subject->createMessage("Hello Observers!");
subject->detach(observer2); // 移除Observer 2
subject->createMessage("New Update Available!");
return 0;
}
改进要点:
-
std::weak_ptr
用于Subject
持有的观察者列表,避免循环引用和内存泄漏。 - 通过
weak_ptr.lock()
检查对象是否仍然有效,如果观察者已被销毁,将其从列表中移除。
2. 性能优化
-
延迟通知:在有大量观察者时,通知所有观察者可能会带来性能开销。如果对实时性要求不高,可以引入批处理或者异步通知机制。可以使用 C++ 标准库中的
std::thread
或std::async
来实现通知的并行或异步操作。
3. 增强可扩展性
-
事件过滤:当前的观察者模式是所有观察者对每个通知都作出响应。可以通过在
notify
方法中增加条件逻辑,使观察者只对某些特定的事件类型作出响应,从而减少不必要的通知。例如,可以引入事件枚举,判断是否应该通知某个观察者。
enum class EventType {
MESSAGE_UPDATE,
DATA_UPDATE
};
class Observer {
public:
virtual ~Observer() {}
virtual void update(EventType type, const std::string& message) = 0;
};
class ConcreteSubject : public Subject {
// 略...
void notify(EventType type) override {
for (auto observer : observers) {
if (auto o = observer.lock()) {
o->update(type, message);
}
}
}
// 可以根据不同的事件类型发送不同的通知
void createMessage(const std::string& message) {
this->message = message;
notify(EventType::MESSAGE_UPDATE);
}
};
改进要点:
- 添加事件类型判断,通知相关的观察者,避免不必要的更新,提升效率。
4. 线程安全
如果你的项目是多线程环境,考虑将 Subject
的 attach()
、detach()
和 notify()
方法添加互斥锁以保证线程安全,避免多线程同时修改观察者列表可能带来的数据竞争。
可以使用 C++11 提供的 std::mutex
实现线程安全:
#include <mutex>
class ConcreteSubject : public Subject {
private:
std::vector<std::weak_ptr<Observer>> observers;
std::string message;
std::mutex mtx; // 互斥锁保证线程安全
public:
void attach(std::shared_ptr<Observer> observer) override {
std::lock_guard<std::mutex> lock(mtx); // 加锁
observers.push_back(observer);
}
void detach(std::shared_ptr<Observer> observer) override {
std::lock_guard<std::mutex> lock(mtx); // 加锁
observers.erase(
std::remove_if(observers.begin(), observers.end(),
[&observer](const std::weak_ptr<Observer>& o) {
return o.lock() == observer;
}),
observers.end());
}
void notify() override {
std::lock_guard<std::mutex> lock(mtx); // 加锁
for (auto it = observers.begin(); it != observers.end();) {
if (auto observer = it->lock()) {
observer->update(message);
++it;
} else {
it = observers.erase(it);
}
}
}
// 其他方法略...
};
改进要点:
- 引入互斥锁确保观察者列表的修改和遍历在多线程下的安全性。
5. 日志功能
可以为观察者模式中的 notify()
添加日志功能,记录每次的通知行为和状态变化。借助 std::ofstream
或其他日志库(如 spdlog
),可以方便地跟踪整个系统的事件传播过程。
总结:
- 使用
std::weak_ptr
避免循环引用。 - 引入 事件类型 过滤以减少不必要的通知。
- 增加 线程安全机制 以支持多线程环境。
- 考虑异步或并行的 性能优化。
- 添加日志以增强 调试能力。
通过这些改进,代码将变得更加健壮、可扩展且高效。