Tôi có triển khai một Mẫu nhà nước nơi mỗi tiểu bang xử lý các sự kiện mà nó nhận được từ hàng đợi sự kiện. Do đó, lớp cơ sở State
có phương thức ảo thuần túy là void handleEvent(const Event*)
. Sự kiện kế thừa lớp cơ sở Event
nhưng mỗi sự kiện chứa dữ liệu của nó có thể thuộc một loại khác (ví dụ: int, string ... hoặc bất kỳ thứ gì). handleEvent
phải xác định loại thời gian chạy của sự kiện đã nhận và sau đó thực hiện downcast để trích xuất dữ liệu sự kiện. Các sự kiện được tạo và lưu trữ động trong hàng đợi (vì vậy, hãy upcasting diễn ra tại đây ...).Làm thế nào để tránh downcast?
Tôi biết rằng downcasting là một dấu hiệu của một thiết kế xấu nhưng là nó có thể tránh nó trong trường hợp này? Tôi đang nghĩ đến Mô hình khách truy cập trong đó lớp cơ sở Nhà nước sẽ chứa trình xử lý ảo cho mỗi sự kiện nhưng sau đó một lần nữa sẽ cần phải diễn ra trong đoạn mã để loại bỏ sự kiện khỏi hàng đợi và chuyển nó tới trạng thái hiện tại. (Ít nhất trong trường hợp này lớn switch(eventID)
sẽ chỉ ở một nơi ...). Mô hình khách truy cập là cách tốt nhất (thực hành tốt nhất) để tránh downcasting?
Đây là pseudo-code (tôi đi qua boost::shared_ptr
trong ví dụ này nhưng downcasting xảy ra anyway):
enum EventID
{
EVENT_1,
EVENT_2,
...
};
class Event
{
EventID id;
public:
Event(EventID id):id(id){}
EventID id() const {return id;}
virtual ~Event() = 0;
};
class Event1 : public Event
{
int n;
public:
Event1(int n):Event(EVENT_1), n(n){}
int getN() const {return n;}
};
class Event2 : public Event
{
std::string s;
public:
Event2(std::string s):Event(EVENT_2), s(s){}
std::string getS() const {return s;}
};
typedef boost::shared_ptr<Event> EventPtr;
class State
{
...
public:
...
virtual ~State() = 0;
virtual void handleEvent(const EventPtr& pEvent) = 0;
};
class StateA : public State
{
...
public:
void handleEvent(const EventPtr& pEvent)
{
switch(pEvent->id())
{
case EVENT_1:
int n = boost::static_pointer_cast<Event1>(pEvent)->getN();
...
break;
case EVENT_2:
std::string s = boost::static_pointer_cast<Event2>(pEvent)->getS();
...
break;
...
}
}
}
Downcast được thực hiện bằng cách gọi '' Event :: accept''. Nó được giải quyết qua vtable thành '' EventBar :: accept'' và '' this'' được truyền từ '' Event'' sang '' EventBar'' trong tiến trình. –
Vì vậy, không có các mẫu/thành ngữ ma thuật nào khác để tránh downcasting? Mối quan tâm duy nhất của tôi với Khách truy cập là số lượng mã lặp lại cần phải được viết. Nhưng có vẻ như đó là giá của việc không bị mất tín hiệu. Tôi sẽ không có vấn đề này nếu tôi chỉ có một lớp Event duy nhất và không cần phải lưu trữ các lớp Event có nguồn gốc trong hàng đợi nhưng điều đó là không thể tránh khỏi. –
@BojanKomazec: ít nhất một cách khác là sử dụng 'boost :: variant':' typedef boost :: biến thể Event; '. Bằng cách xóa cấu trúc phân cấp, bạn xóa các tệp bị hủy bỏ :) –