Rob*_*wko 6 c++ design-patterns rtti
我正在使用外部库,需要创建一个观察者模式,其中观察者来自属于该库的对象.我不想从库中更改基类,同时我必须使用这个不可更改的基类的引用/指针列表.除此之外,库构造了对象列表,我需要从中筛选出适合观察者的对象.
我写的代码大致相当于:
#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();
}
Run Code Online (Sandbox Code Playgroud)
然后我使用" BaseOfObserver添加主题意识"到我的其他派生类型.这样我就不必为我想要实现的每个特定观察者重复一个if语句.
它似乎工作正常,但这是一个设计错误?有没有更好的方法来构建没有RTTI机制的观察者列表并且不干扰库类?
您的问题归结为拥有一个基指针序列,并且只想使用该序列中属于特定派生类型的元素。
dynamic_cast当然有效,但在这种情况下,这是没有必要的。如果要将所需的指针保存在单独的容器中,则无需在也包含其他指针的容器中查找它们。
std::vector<Observer *> observers {new Observer()};
Run Code Online (Sandbox Code Playgroud)
您仍然可以通过复制观察者指针来拥有包含所有指针的容器。
std::vector<BaseFromLibrary *> all {new BaseFromLibrary()};
all.reserve(all.size() + observers.size());
all.insert(all.end(), observers.begin(), observers.end());
Run Code Online (Sandbox Code Playgroud)
或者,如果您想迭代单独容器中的所有元素而不进行复制,则可以使用 Boost.Range 中的boost::join之类的东西。
您可以轻松地复制观察者指针,而无需使用dynamic_cast。
s.observers.insert(observers.begin(), observers.end());
Run Code Online (Sandbox Code Playgroud)
当然,如果这就是您要做的全部事情,那么您可以s.observers首先将其用作观察者的原始容器。
作为旁注,您的示例程序会泄漏内存。避免手动内存管理以防止出现这些情况。