1. 从面试题看观察者模式的深度考察
"请你讲讲C++中的观察者模式"——这个看似基础的设计模式问题,在实际面试中往往成为区分候选人的分水岭。最近一位字节跳动面试官对候选人"7点回答"的评价"不够深",恰恰揭示了工业级C++开发中对设计模式理解的严苛要求。观察者模式在事件驱动系统、GUI框架、游戏引擎等场景中无处不在,但真正要写出生产环境可用的实现,需要考虑的远不止UML图上那几个简单的类和箭头。
在QT的信号槽、Boost.Signals2等知名库中,观察者模式的实现都包含了大量工程化细节。我曾参与过一个日均处理千万级事件的分布式系统开发,其中观察者模式的线程安全问题就让我们团队踩了整整两周的坑。本文将结合这些实战经验,剖析那些容易被教科书忽略的实现细节。
2. 观察者模式的核心实现与内存陷阱
2.1 基础结构的典型实现
我们先看一个最朴素的观察者模式实现:
cpp复制class Observer {
public:
virtual ~Observer() = default;
virtual void update(const std::string& msg) = 0;
};
class Subject {
std::vector<Observer*> observers_;
public:
void attach(Observer* obs) {
observers_.push_back(obs);
}
void notifyAll(const std::string& msg) {
for (auto obs : observers_) {
obs->update(msg); // 致命缺陷:裸指针可能已失效
}
}
};
这个实现至少有3个严重问题:
- 使用原始指针导致生命周期管理困难
- 遍历通知过程中容器可能被修改
- 异常安全没有保障
2.2 智能指针的正确使用姿势
现代C++项目应该优先使用智能指针。但具体选择哪种需要仔细考量:
| 智能指针类型 | 适用场景 | 在观察者模式中的注意事项 |
|-------------|------
