重构switch语句的设计模式

bpw*_*621 6 c++ refactoring design-patterns

我在标题中有类似的内容

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 { ... };
Run Code Online (Sandbox Code Playgroud)

并用作

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;
}
Run Code Online (Sandbox Code Playgroud)

这似乎是一种相当普遍并且非常适合重构的情况.应用设计模式(或基本的C++语言特性重新设计)来重构此代码的最佳方法是什么?

我已经读过Command模式通常用于重构switch语句,但这似乎只适用于在执行任务的算法之间进行选择.这是工厂或抽象工厂模式适用的地方(我不是很熟悉)?双重派遣?

我试图忽略尽可能多的无关紧要的背景,但如果我错过了重要的事情,请告诉我,我会编辑包含它.此外,我找不到任何类似的东西,但如果这是重复只是重定向到适当的SO问题.

Adr*_*gan 5

您可以使用Factory Method模式,该模式根据您从流中查看的值创建基类(派生类)的正确实现.

  • 工厂方法,如您提供的Wikipedia链接所解释的,仍然有一个`switch`语句,它只是隐藏在工厂方法中. (5认同)

das*_*ang 2

将 Types 和 type_ 从 MsgBase 中取出,它们不属于那里。

如果您想要完全奇特,请向工厂注册所有派生类型以及工厂将用来知道要做什么的标记(例如“类型”)。然后,工厂在其表中查找反序列化时的令牌,并创建正确的消息。

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);
Run Code Online (Sandbox Code Playgroud)

Create 静态方法分配一个新的 DerivedMessage 并将其反序列化,Serialize 方法写入令牌(在本例中为Hash("DerivedMessage")),然后序列化自身。其中之一可能应该测试 isRegistered,这样它就不会被链接器完全剥离。

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