我在标题中有类似以下内容的内容
class MsgBase
{
public:
unsigned int getMsgType() const { return type_; }
...
private:
enum Types { MSG_DERIVED_1, MSG_DERIVED_2, ... MSG_DERIVED_N };
unsigned int type_;
...
};
class MsgDerived1 : public MsgBase { ... };
class MsgDerived2 : public MsgBase { ... };
...
class MsgDerivedN : public MsgBase { ... };,并用作
MsgBase msgHeader;
// peeks into the input stream to grab the
// base class that has the derived message type
// non-destructively
inputStream.deserializePeek( msgHeader );
unsigned int msgType = msgHeader.getMsgType();
MsgDerived1 msgDerived1;
MsgDerived2 msgDerived2;
...
MsgDerivedN msgDerivedN;
switch( msgType )
{
case MSG_DERIVED_1:
// fills out msgDerived1 from the inputStream
// destructively
inputStream.deserialize( msgDerived1 );
/* do MsgDerived1 processing */
break;
case MSG_DERIVED_2:
inputStream.deserialize( msgDerived2 );
/* do MsgDerived1 processing */
break;
...
case MSG_DERIVED_N:
inputStream.deserialize( msgDerivedN );
/* do MsgDerived1 processing */
break;
}这似乎是一种相当常见且非常适合重构的情况。应用设计模式(或基本C++语言功能重新设计)来重构此代码的最佳方式是什么?
我读到过Command模式通常用于重构switch语句,但似乎只有在选择算法来完成任务时才适用。这是一个工厂或抽象工厂模式适用的地方吗(我也不是很熟悉)?双重调度?
我试着省略掉尽可能多的无关紧要的上下文,但是如果我错过了一些重要的东西,请让我知道,我会编辑并将其包括在内。此外,我找不到任何类似的东西,但如果这是重复的,请将我重定向到适当的SO问题。
发布于 2010-08-05 00:28:07
将类型和type_从MsgBase中提取出来,它们不属于那里。
如果你想得到完全花哨的东西,可以向工厂注册所有的派生类型以及工厂用来知道要做什么的令牌(例如'type')。然后,工厂在其表中的反序列化时查找该令牌,并创建正确的消息。
class DerivedMessage : public Message
{
public:
static Message* Create(Stream&);
bool Serialize(Stream&);
private:
static bool isRegistered;
};
// sure, turn this into a macro, use a singleton, whatever you like
bool DerivedMessage::isRegistered =
g_messageFactory.Register(Hash("DerivedMessage"), DerivedMessage::Create);Create static方法分配新的DerivedMessage并对其进行反序列化,Serialize方法写入令牌(在本例中为Hash("DerivedMessage")),然后序列化自身。他们中的一个可能应该测试isRegistered,这样它就不会被链接器剥离。
(值得注意的是,此方法不需要枚举或其他“所有可能存在的静态列表”。此时,我想不出另一种方法在某种程度上不需要循环引用。)
发布于 2010-08-05 00:03:47
您可以使用Factory Method模式,它基于从流中窥视的值创建基类(派生类)的正确实现。
发布于 2010-08-05 00:28:03
这种转换并不全是坏事。这是实现工厂模式的一种方式。它很容易测试,它使得理解可用对象的整个范围变得很容易,并且它对覆盖率测试很好。
另一种技术是在枚举类型和工厂之间建立映射,以便从数据流生成特定的对象。这会将编译时开关转换为运行时查找。映射可以在运行时构建,因此可以添加新类型,而无需重新编译所有内容。
// You'll have multiple Factories, all using this signature.
typedef MsgBase *(*Factory)(StreamType &);
// For example:
MsgBase *CreateDerived1(StreamType &inputStream) {
MsgDerived1 *ptr = new MsgDerived1;
inputStream.deserialize(ptr);
return ptr;
}
std::map<Types, Factory> knownTypes;
knownTypes[MSG_DERIVED_1] = CreateDerived1;
// Then, given the type, you can instantiate the correct object:
MsgBase *object = (*knownTypes[type])(inputStream);
...
delete object;https://stackoverflow.com/questions/3407409
复制相似问题