首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >重构switch语句的设计模式

重构switch语句的设计模式
EN

Stack Overflow用户
提问于 2010-08-04 23:59:58
回答 4查看 3.1K关注 0票数 6

我在标题中有类似以下内容的内容

代码语言:javascript
运行
复制
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 { ... };

,并用作

代码语言:javascript
运行
复制
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问题。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-08-05 00:28:07

将类型和type_从MsgBase中提取出来,它们不属于那里。

如果你想得到完全花哨的东西,可以向工厂注册所有的派生类型以及工厂用来知道要做什么的令牌(例如'type')。然后,工厂在其表中的反序列化时查找该令牌,并创建正确的消息。

代码语言:javascript
运行
复制
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,这样它就不会被链接器剥离。

(值得注意的是,此方法不需要枚举或其他“所有可能存在的静态列表”。此时,我想不出另一种方法在某种程度上不需要循环引用。)

票数 2
EN

Stack Overflow用户

发布于 2010-08-05 00:03:47

您可以使用Factory Method模式,它基于从流中窥视的值创建基类(派生类)的正确实现。

票数 5
EN

Stack Overflow用户

发布于 2010-08-05 00:28:03

这种转换并不全是坏事。这是实现工厂模式的一种方式。它很容易测试,它使得理解可用对象的整个范围变得很容易,并且它对覆盖率测试很好。

另一种技术是在枚举类型和工厂之间建立映射,以便从数据流生成特定的对象。这会将编译时开关转换为运行时查找。映射可以在运行时构建,因此可以添加新类型,而无需重新编译所有内容。

代码语言:javascript
运行
复制
// 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;
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3407409

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档