2009-07-06 1 views
0

私はクライアント/サーバーアプリケーションと非常に簡単な通信プロトコルを持っています。より正確には、サーバーが送信する一連のコマンドと、クライアントが実行できる一連の要求です。次のようにネットワークメッセージ用のクラスアーキテクチャを設計する

考え方は次のとおりです。

コマンドがサーバによって行われた場合、クライアントはそれを実行する必要があります。 要求が行われると、サーバーはアクセス許可をチェックし、すべてがOKであれば要求を許可します。

アプリケーションは、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()を追加する必要があります。また、別のリクエストへのポインタを1つのコンテナに格納する場合は、Requestが多型ではないため、dynamic_castを使用することはできません。明らかな(曖昧な)解決策は、make(int n, ...)の定義を使用し、stdarg.hを使用して異なる引数を抽出しますが、これはプログラマーにとって安全でないと紛らわしいと考えています。

私の考えには明らかに設計上の欠陥があります。私は既に念頭に置いて解決策を持っていますが、私はちょうど不思議です。だから、人々はどのようにこの問題に取り組んでいますか?どのような種類のオブジェクトアーキテクチャを使用しますか?この問題を解決する簡単なアプローチはありますか?できるだけシンプルにし、実際のプロトコルをそのまま維持すること(タブ区切りの文字列で、どのメッセージであるかを示す第1パラメータ付き)以外は、特別な要件はありません。

答えて

1

あなたのデザインの問題は、あまりにも多くの機能を1つのクラスに詰め込もうとしたことだと思います。たとえば、数値データまたは文字列を含むメッセージを構築/解析する部分(すなわち、シリアライゼーション)は、基本的な接続ロジックとは別にする必要があります。

チェックアウトBoost.Serializationあなたは追加のライブラリを使用することを許可されている場合。 BoostにはASIOという非常に素晴らしいネットワークライブラリもあります。あなたがブーストを使用することが許可されていない場合でも、おそらく自分のライブラリの設計を参考にする必要があります。

+0

私は心の中で持っていたソリューションの一種です。実際の解析と実行を分けてください。私。作成された各メッセージにはシリアライズ可能な構造があり、それ以降は引き継がれます。次に、構造体のすべてのメンバーであるため、引数を取らない仮想関数 'make()'を作成することができます。 :) – sneg

+0

申し訳ありません。私が 'make()'を書いたとき、私は間違いを犯しました。私は要求/コマンドを実行する実行機能を意味しました。 – sneg

+1

もう一つ考慮すべきことは、Visitorのパターンを解析してコードをシリアライズすることです。あなたが扱う必要があるメッセージクラスの定義済みのセットがあるとき、それは素晴らしい仕事をしました。 – oscarkuo

1

はい、あなたは「コマンド/要求はタブ区切りの文字列である」と言う:kuosonが言ったように、代わりに、すべてのメッセージが構築されている...「異なるメッセージが異なる引数を取ることができる」というのは本当ではないですよタブで区切られた文字列から

+0

私が言ったことは、メッセージを作成するときに、データをシリアライズする必要があるかもしれないということです。私。現在の実装に従えば、メッセージを作成して3つの整数を送る 'make(int x、int y、int z)'のようなものがあります。受信者はタブ区切り文字列を取得します。 :) – sneg

関連する問題