2009-07-06 31 views
0

我有客户端/服务器应用程序和一个非常简单的通信协议。更准确地说,它是一组服务器发送的命令和一组客户端可以创建的请求。为网络消息设计一个类架构

的想法如下:

当命令是由服务器进行,​​客户端具有执行它。 发出请求时,服务器检查权限,如果一切正常,则授予请求。

该应用程序是用C++编写,我得到了稍微卡设计架构,这种通信协议。假设命令/请求是一个制表符分隔的字符串,其中第一个参数是消息的名称,我打算创建一个MessageManager类,它将所有消息存储在散列表中,并在必要时检索它们。这里的问题是这样的:

typedef std::vector<std::string> ArgArray; 
class Request : public Message 
{ 
public: 
    Request(const char *name) : Message(name) { } 
#ifdef CLIENT 
    /** problem here **/ 
    virtual void make(...) = 0; 
#elif defined SERVER 
    virtual void grant(const Client &c, const ArgArray &params) const = 0; 
protected: 
    virtual void checkPermissions(const Client &c, const ArgArray &params) const = 0; 
#endif 
}; 

因为不同的消息可以采取不同的参数来构建我真的不能创建一个完整的接口。例如,某些消息可能需要构造一个简单的字符串,而其他消息可能需要一些数字数据。这使事情变得复杂,并使得设计有点不整洁。我必须通过从接口定义中省略make()来解决问题,并简单地为每个请求添加不同的make()。另外,如果我希望在一个容器中存储指向不同请求的指针,我不能使用dynamic_cast,因为Request不是多态类型。一个明显的(不整洁的)解决方案将使用make(int n, ...)定义并使用stdarg.h来提取不同的参数,但我认为这对程序员来说是不安全和令人困惑的。

我的想法显然存在设计缺陷。我已经有了一个解决方案,但我只是想知道,SO的人们将如何解决这个问题?你会使用什么样的对象架构?有没有更简单的方法可以解决这个问题?除了保持尽可能简单并保持实际协议原样(带有第一个参数的制表符分隔字符串表明它是哪个消息)之外,没有任何特定的要求。

回答

1

我认为你设计中的问题是你试图将太多的功能塞进一个类中。例如,构造/解析消息以包含数字数据或字符串(即序列化)的部分应该与基础连接逻辑分开。

退房Boost.Serialization,如果你被允许使用额外的库。 Boost有一个非常漂亮的网络库,名为ASIO。即使你不允许使用提升,你应该咨询他们的图书馆设计。

+0

这是一种我在心中具有的解决方案。将实际分析与执行分开。即为每个创建的消息都有一个可序列化的结构,并且继续传递。然后,我们可以创建虚函数`make()`,它不需要任何参数,因为它们都是结构的成员。 :) – sneg 2009-07-06 23:48:49

+0

对不起。当我写'make()`时,我犯了一个错误。我的意思是执行请求/命令的执行功能。 – sneg 2009-07-06 23:50:33

1

是的,你说,“命令/请求是一个制表符分隔字符串”:这样kuoson说,这是不正确的,“不同的消息可以采取不同的参数” ...相反,正在建设中的所有消息来自制表符分隔的字符串。