调度自动化

dispatch automation

本文关键字:自动化 调度      更新时间:2023-10-16

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

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

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

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

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

最后一个看起来像这样:

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

现在,缺少的只是将 TBuffer 转换为 TFooArgs 的部分,调用正确的方法,然后将 TFooResult 转换回 TBuffer 的部分(转换是微不足道的)。

不同的

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

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

通用代码很好。

  1. 创建两种转换方法,一种从TBuffer转换为XArgs,另一种从XResult转换为TBuffer
  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;
};

注意:作为作弊,我们将&a传递给from_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);
}