2016-01-11 22 views
6

Tôi đang làm việc với thư viện bên ngoài và cần tạo mẫu quan sát nơi quan sát được bắt nguồn từ một đối tượng thuộc về thư viện. Tôi không muốn thay đổi lớp cơ sở từ thư viện và đồng thời tôi phải sử dụng danh sách các tham chiếu/con trỏ tới lớp cơ sở không thay đổi này. Ngày đầu này thư viện xây dựng danh sách các đối tượng mà từ đó tôi cần phải sàng lọc những người phù hợp để được quan sát viên.Sử dụng RTTI với các đối tượng có nguồn gốc từ thư viện bên ngoài

Mã tôi đã viết là tương đương với điều này:

#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(); 
} 

Sau đó, tôi sử dụng BaseOfObserver thêm "nhận thức chủ đề" với các loại có nguồn gốc khác của tôi. Bằng cách này tôi không phải lặp lại câu lệnh if cho từng người quan sát cụ thể mà tôi muốn thực hiện.

Dường như hoạt động tốt, nhưng đó có phải là lỗi thiết kế không? Có cách nào tốt hơn để xây dựng danh sách người quan sát mà không có cơ chế RTTI và không can thiệp vào các lớp thư viện không?

Trả lời

0

Sự cố của bạn sẽ có một chuỗi các con trỏ cơ sở và chỉ muốn sử dụng các phần tử của chuỗi đó là một loại có nguồn gốc cụ thể.

dynamic_cast chắc chắn hoạt động, nhưng trong trường hợp này, không cần thiết. Nếu bạn giữ các con trỏ mong muốn trong một thùng chứa riêng biệt, bạn sẽ không cần phải tìm chúng trong một thùng chứa các con trỏ khác nữa.

std::vector<Observer *> observers {new Observer()}; 

Bạn vẫn có thể chứa một hộp chứa tất cả các con trỏ bằng cách sao chép con trỏ quan sát.

std::vector<BaseFromLibrary *> all {new BaseFromLibrary()}; 
all.reserve(all.size() + observers.size()); 
all.insert(all.end(), observers.begin(), observers.end()); 

Hoặc, bạn có thể sử dụng thứ gì đó như boost::join từ Boost.Range nếu bạn muốn lặp qua tất cả các phần tử trong vùng chứa riêng mà không sao chép.

Bạn có thể sao chép một cách trivially con trỏ quan sát mà không có dynamic_cast.

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

Tất nhiên, nếu đó là tất cả các bạn đang đi làm, sau đó bạn có thể đã sử dụng s.observers như container ban đầu cho các quan sát viên ở nơi đầu tiên.

Là một sidenote, chương trình ví dụ của bạn làm rò rỉ bộ nhớ. Tránh quản lý bộ nhớ thủ công để ngăn chặn những tình huống đó.

+0

Nếu tôi hiểu chính xác bạn, bạn đang đề nghị chia 'danh sách' khỏi ví dụ của tôi. Tôi có thể quên nhấn mạnh rằng đây cũng là điều tôi không thể làm. Thư viện xây dựng danh sách đó một mình và tôi không muốn can thiệp vào quá trình đó. Tôi sẽ cố gắng chỉnh sửa điều đó. Điểm bị rò rỉ bộ nhớ. –

Các vấn đề liên quan