抽象/重构此开关/案例的好方法是什么?

时间:2014-04-10 16:13:51

标签: c++ templates protocol-buffers

在项目的源代码中,我看到一个300行的switch / case子句。但它的结构非常好,因为每一个案例都是这样的:

        case X:
        {
            msg_type_for_X msg;

            if (msg.ParseFromArray (m_readBuffer))
                recv_X (msg);
        }
            break;

这让我希望把它分成20行。对于每个案例X,类msg_type_for_X是由protobuf定义的类。对我来说这似乎很棘手,因为编译器无法知道msg具有什么类型。那么人们如何重构这样的东西呢?或者人们只是不管它?

2 个答案:

答案 0 :(得分:2)

您可以在宏中使用令牌粘贴。看here

这将是:

#define CASE_MSG(X) \
    case X: \
    { \
        msg_type_for_##X msg; \
        if (msg.ParseFromArray (m_readBuffer)) \
            recv_##X (msg); \
    } \
    break;

还有其他方法可以做这种事情,并且有一个msg_type_for_X结构数组,你将它们全部初始化,然后你甚至不需要使用一个案例:

if (messages[X].ParseFromArray(m_readBuffer))
       messages[X].recv(msg);

当然,需要进行一些重构才能将recv_X作为消息解析器的一种方法。

答案 1 :(得分:0)

从简单的基本界面开始,如

struct IMsgOperation { virtual int indexOf() const = 0; virtual bool ParseFromArray(param of type m_readBuffer) = 0; /*virt desturctor and etc*/}

然后为每个X类型定义特定的类:

struct XMsgOperation : public IMsgOperation { int indexOf() const { return hardcode_index_of_X_from_some_enum; }; virtual bool ParseFromArray(); }

并实施它; 为每个XMsgOperation创建实例数组,

vector<IMsgOperation *> parsers(num_of_parsers, NULL); 

比填充数组

IMsgOperation *pOp=new FooMsgOperation; parsers[pOp->indexOf()]=pOp; ...

并发明映射函数以将X的每个值映射到正确的索引

static int IMsgOperation::type2index(type_of_X X) { switch(X) { case X: return 0; ...} }

比它可以使用:

parsers[IMsgOperation::type2index(type_of_X X)]->ParseFromArray(m_readBuffer)

注意,如果type_of_X是整数种类,那么您可以将type_of_X的值组织为线性顺序并消除type2index。以上不包含任何安全检查,添加它们的味道。