2012-06-07 34 views
0

我自己并不完全确定我在这里要求什么,所以请耐心等待我一秒。调度自动化

基本上,我有有,除其他事项外,能够处理从一些外部源接收命令的应用程序,比方说,一个插座。

每个命令使用特定两个数据结构,此命令 - 一个结构保存一组相关于该命令的处理参数时,另一个接收一些得到的数据。

当然,数据传输处理程序类并不知道哪些命令使用其结构,因此接收到的命令之后调用的第一件事情是这样的外观:

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

,最后一个看起来是这样的:

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

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

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

所以我的问题 - 是它可以自动完成繁琐和容易出错的任务是什么?最好到定义一个新的消息处理方法就足够了,但我愿意妥协。

+0

欢快的话,你跟着我的建议。那么谁在笑呢? –

回答

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); 
}