0

我自己并不确定我在这里要求什么,所以请耐心等待。

基本上,我有一个应用程序,除其他外,它必须能够处理从某个外部源接收到的命令,比如说一个套接字。

每个命令使用两个特定于该命令的数据结构——一个结构包含一组与该命令的处理相关的参数,另一个接收一些结果数据。

自然,数据传输处理程序类对哪个命令使用哪个结构一无所知,因此在收到命令后调用的第一件事如下所示:

CSocketHandler::ReceiveCommand(int CommandCode, const TBuffer& Args, TBuffer& Result);

最后一个看起来像这样:

CClassBar::ProcessCommandFoo(const TFooArgs& Args, TFooResult& Result);

现在,所缺少的只是将 TBuffer 转换为 TFooArgs,调用正确的方法,然后将 TFooResult 转换回 TBuffer 的部分(转换很简单)。

不同的处理程序类和命令的数量肯定会很大,所以我在这里看到的是一个三英里长的方法,它对不同的数据类型做同样的事情,然后一遍又一遍地调用不同的函数。

所以我的问题 - 是否可以自动化这个繁琐且容易出错的任务?最好只定义一个新的消息处理方法就足够了,但我愿意妥协。

4

1 回答 1

2

通用代码很好。

  1. 创建两个转换方法,一个从TBufferXArgs,另一个从XResultTBuffer
  2. 创建自动命令包装器
  3. 实现一个map自动分派给那些包装器

您可以通过指向函数的指针或继承来做到这一点,我想继承会更容易......

class BaseCommand {
public:
    virtual ~BaseCommand() {}

    virtual TBuffer invoke(TBuffer const& tb) = 0;
};

template <typename Args, typename Result>
class CommandT: public BaseCommand {
public:
    virtual TBuffer invoke(TBuffer const& tb) {
        Args const a = from_buffer(tb, &a); // free function
        Result const r = this->invoke(a);
        return to_buffer(r);            // free function
    }

private:
    virtual Result invoke(Args const&) = 0;
};

注意:作为作弊,我们通过&afrom_buffer获得自动参数推导,预计指针未使用。

所以,让我们假设我们有我们的论点和结果(两者都int更容易):

int from_buffer(TBuffer const& tb, int const*) {
    return tb.asInt();
}

TBuffer to_buffer(int i) {
    return TBuffer(i);
}

然后我们可以实现一个处理的命令int

class IntCommand: public CommandT<int, int> {
    virtual int invoke(int const& i) override { return i; }
};

好的,让我们继续进行调度。这个想法是将每个命令注册到它的 ID。

template <typename T>
std::unique_ptr<BaseCommand> make_command() { return std::unique_ptr<T>(new T()); }

static std::map<int, std::unique_ptr<BaseCommand>> Commands;

int main() {
    Commands.insert(std::make_pair(1, make_command<IntCommand>()));
    // lots of them...

    // starts processing
}

SocketHandler我们有:

void SocketHandler::ReceiveCommand(int code, TBuffer const& a, TBuffer& r) {
    typedef std::map<int, std::unique_ptr<BaseCommand>>::const_iterator const_it;

    const_it it = Commands.find(code);
    if (it == Commands.end()) {
        std::cerr << "Unknown command: " << code << "\n";
        throw std::runtime_error("Unknown command");
    }

    r = it->second->invoke(a);
}
于 2012-06-07T15:49:39.193 回答