我正在使用外部库,需要创建一个观察者模式,其中观察者来自属于该库的对象。我不想从库中更改基类,同时我必须使用这个不可更改的基类的引用/指针列表。除此之外,库构造了对象列表,我需要从中筛选出适合观察者的对象。
我写的代码大致相当于:
#include <iostream>
#include <vector>
#include <memory>
// This class is from an external library which I don't want to chagne
class BaseFromLibrary {
public:
virtual ~BaseFromLibrary() {}
};
class BaseOfObserver {
public:
void notify() { std::cout << "What-ho!\n"; };
};
class Observer : public BaseFromLibrary, public BaseOfObserver {};
class Subject {
public:
std::vector<std::shared_ptr<Observer>> observers;
void notifyObervers() {
for (auto &o : observers)
(*o).notify();
}
};
int main() {
// This list is constructed by the library and I cannot interfere with that
// process
std::vector<std::shared_ptr<BaseFromLibrary>> list{
std::make_shared<BaseFromLibrary>(), std::make_shared<Observer>()};
Subject s;
for (auto &e : list)
if (std::dynamic_pointer_cast<Observer>(e) != nullptr)
s.observers.push_back(std::dynamic_pointer_cast<Observer>(e));
s.notifyObervers();
}
然后我使用BaseOfObserver
向我的其他派生类型添加“主题意识”。这样我就不必为我想要实现的每个特定观察者重复一个if语句。
它似乎工作正常,但这是一个设计错误?有没有更好的方法来构建没有RTTI机制的观察者列表并且不干扰库类?
答案 0 :(得分:0)
你的问题归结为拥有一系列基本指针,并且只想使用特定派生类型的序列元素。
dynamic_cast
当然有效,但在这种情况下,没有必要。如果要将所需的指针保存在单独的容器中,则不需要在包含其他指针的容器中查找它们。
std::vector<Observer *> observers {new Observer()};
通过复制观察者指针,你仍然可以拥有一个包含所有指针的容器。
std::vector<BaseFromLibrary *> all {new BaseFromLibrary()};
all.reserve(all.size() + observers.size());
all.insert(all.end(), observers.begin(), observers.end());
或者,如果你想在不复制的情况下迭代单独容器中的所有元素,你可以使用Boost.Range中的boost::join之类的内容。
您可以在没有dynamic_cast的情况下轻松复制观察者指针。
s.observers.insert(observers.begin(), observers.end());
当然,如果您要做的就是这样,那么您可以首先使用s.observers
作为观察员的原始容器。
作为旁注,您的示例程序会泄漏内存。避免手动内存管理以防止这些情况。