У меня есть два вида сообщений: MessageA
а также MessageB
оба получены из абстрактного класса IMessage
содержащий чисто виртуальный метод std::string toString()
, Поэтому я могу преобразовать каждое сообщение в его строковое представление с указателем на базовый класс. Все в порядке. Однако мне нужно как-то построить сообщение (конкретный тип сообщения) из строки, например:
MessageA* msg = [something].fromString( str )
, Я хотел бы получить NULL, если данная строка не подходит для построения MessageA
, Я вижу два подхода к этой задаче:
а) MessageFactory
с dynamic_cast
class MessageFactory
{
IMessage* fromString( const std::string& str );
};
...
MessageFactory mf;
MessageA* msg = dynamic_cast< MessageA* >( mf.fromString( str ) );
if ( msg ) { ... }
Тем не менее, это использует dynamic_cast, который я хотел бы избежать.
б) фабричный метод в каждом производном классе
static MessageA* fromString( const std::string& str )
{
return stringIsOk( str ) ? new MessageA() : NULL;
}
Есть ли лучшее решение? Должен ли я что-то изменить в общем дизайне? Спасибо.
ОБНОВИТЬ
Когда-нибудь я знаю, какое сообщение я должен получить из строки, т.е.
void sendRequest()
{
...
std::string response;
MessageA* msg = fromString( response );
// here i should only check if string is valid for MessageA
}
но иногда я не знаю, что будет со мной
void processMessage( const std::string& str )
{
IMessage* msg = fromString( str );
if ( msg )
{
MessageA* msgA = dynamic_cast< MessageA* >( msg );
if ( msgA )
...
}
}
Вы можете сделать все классы производными от IMessage
зарегистрировать себя (или, скорее, конкретную фабрику) с MessageFactory
класс статически при запуске программы. Это может быть достигнуто с помощью некоторого статического экземпляра. IMessage
интерфейс должен иметь чистый виртуальный метод canConstructFrom(string&)
так, что когда строка приходит, вы передаете это MessageFactory
и фабрика узнает, какой из производных классов может быть создан из этой строки, и создаст экземпляр правильного.
Других решений пока нет …