2016-01-11 26 views
6

我正在使用外部庫,並且需要創建一個觀察者模式,其中觀察者是從屬於該庫的對象派生的。我不想從庫中更改基類,同時我必須使用這個不可更改基類的引用/指針列表。最重要的是,這個庫構造了我需要篩選適合觀察者的對象列表。將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(); 
} 

然後我用BaseOfObserver爲「主體意識」添加到我的其他派生類型。這樣我就不必爲每個想要實現的特定觀察者重複一個if語句。

它似乎工作正常,但是這是一個設計錯誤?有沒有更好的方法來構建沒有RTTI機制的觀察者列表並且不干擾庫類?

回答

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::join從Boost.Range。

您可以簡單地複製觀察者指針而不使用dynamic_cast。

s.observers.insert(observers.begin(), observers.end()); 

當然,如果這就是你要做的,那麼你也可以使用s.observers作爲擺在首位觀察員原來的容器。

作爲旁註,您的示例程序會泄漏內存。避免手動內存管理來防止這些情況。

+0

如果我正確理解你,你建議將我的例子中的'list'分開。我可能忘記強調這也是我不能做的事情。圖書館構建了它自己的列表,我不想幹涉這個過程。我會嘗試編輯它。 有關內存泄漏的問題。 –

相關問題