1

私は複数のコンポーネントを持つ製品に取り組んでいます。それらのほとんどは C++ で記述されていますが、1 つが C で記述されています。情報が IPC を介して各コンポーネントを通過するシナリオがよくあります。

これらのメッセージを構造体を使用して定義し、それらをメッセージにパックしてメッセージ キュー経由で送信できるようにします。これらの構造体は、「転送」のみを目的として設計されており、その目的のみを果たすように記述されています。私が直面している問題は次のとおりです。プログラマーは構造体を保持し、それを情報の長期的なコンテナーとして使用しています。

私の目には、これは問題です。

1) トランスポート構造を変更すると、すべてのコードが壊れます。このシナリオに遭遇しないように、ここでカプセル化する必要があります。

2) メッセージ構造体は非常に厄介で、情報を転送するためだけに設計されています...この構造体が、これらの他のコンポーネントのこのデータに (長期的に) アクセスする最も便利な形式になる可能性は非常に低いようです。

私の質問は、この誤用をプログラムで防ぐにはどうすればよいですか? これらの構造物は輸送にのみ使用できるように強制したいと思います。

編集:ここでできる限りの例を提供しようとします:

struct smallElement {
    int id;
    int basicFoo;
};

struct mediumElement {
    int id;
    int basicBar;
    int numSmallElements;
    struct smallElement smallElements[MAX_NUM_SMALL];
};

struct largeElement {
    int id;
    int basicBaz;
    int numMediumElements;
    struct mediumElement[MAX_NUM_MEDIUM];
};

その結果、ユーザーは必要なデータを largeElement から抽出してニーズを満たすクラスに入れるのではなく、単に「largeElement」に固執することになります。

4

5 に答える 5

2

メッセージ構造を定義するとき (C++ では、C では有効ではありません)、次のことを確認します。

  1. メッセージオブジェクトはコピー可能です
  2. メッセージオブジェクトは一度だけ構築する必要があります
  3. 構築後にメッセージ オブジェクトを変更することはできません

メッセージが引き続きポッドになるかどうかはわかりませんが、メモリの観点からは同等だと思います。

これを達成するためにすべきこと:

  1. すべてのメンバーをセットアップする一意のコンストラクターを 1 つ持つ
  2. すべてのメンバーを非公開にする
  3. const メンバー アクセサーを持つ

たとえば、次のようにすることができます。

struct Message
{
   int id;
   long data;
   Info info;
};

次に、これが必要です:

class Message // struct or whatever, just make sure public/private are correctly set
{
public:
   Message( int id, long data, long info ) : m_id( id ), m_data( data ), m_info( info ) {}

   int id() const { return m_id; }
   long data() const { return m_data; }
   Info info() const { return m_info; }

private:

   int m_id;
   long m_data;
   Info m_info;

};

これで、ユーザーはメッセージを作成して読み取ることができますが、途中で変更することはできず、データ コンテナーとしては使用できなくなります。ただし、1 つのメッセージを保存することはできますが、後で変更することはできないため、メモリにのみ役立ちます。


または.... 「ブラックボックス」を使用できます。

  1. メッセージ層をライブラリーに分離します (まだ分離していない場合)。
  2. クライアント コードは、メッセージ構造体の定義にまったく公開しないでください。したがって、ヘッダーを提供したり、非表示にしたりしないでください。
  3. ここで、メッセージを送信する関数を提供します。これは、(内部で) メッセージを作成して送信します。それはコードを読むのにも役立ちます。
  4. メッセージを受信するときに、クライアント コードに通知する方法を提供します。ただし、メッセージを直接提供しないでください!!! それらをライブラリ内のどこかに(おそらく一時的に、または生涯ルールなどを使用して)保管してください。おそらく一種のマネージャーなどに保管してください。ただし、ブラックボックス内に保管してください。一種のメッセージ識別子を提供するだけです。
  5. 構造体を公開せずにメッセージから情報を取得する関数を提供します。これを達成するには、いくつかの方法があります。この場合、名前空間に集められた関数を提供します。これらの関数は、最初のパラメーターとしてメッセージ識別子を要求し、メッセージから 1 つのデータのみを返します (必要に応じて完全なオブジェクトになる可能性があります)。

そうすれば、ユーザーは定義を持っていないため、構造体をデータコンテナーとして使用できません。彼らはデータにアクセスすることしかできません。

これには 2 つの問題があります。明らかなパフォーマンス コストと、記述と変更が明らかに重いことです。たぶん、コードジェネレーターを使用する方が良いでしょう。Google Protobuf には、この分野の優れたアイデアがたくさんあります。


しかし、最善の方法は、彼らのやり方がすぐに、または後で破綻する理由を彼らに理解させることです。

于 2011-03-16T18:31:29.840 に答える
2

プログラマーがこれを行っているのは、必要な機能を実現するための抵抗が最も少ない最も簡単な方法だからです。データが適切なアクセサーを備えたクラスにある場合は、データにアクセスする方が簡単かもしれませんが、その場合、そのクラスを作成し、変換関数を作成する必要があります。

彼らの怠惰さを利用して、正しいことをするための最も簡単な道を作りましょう。作成するメッセージ構造体ごとに、変換メソッドを備えた優れたインターフェイスを使用してデータを格納およびアクセスするための対応するクラスを作成し、メッセージをクラスに入れるためのワンライナーを作成します。クラスにはより優れたアクセサ メソッドがあるため、間違ったことをするよりも簡単に使用できます。例えば:

msg_struct inputStruct = receiveMsg();
MsgClass msg(inputStruct);
msg.doSomething()
...
msg_struct outputStruct = msg.toStruct();

簡単な方法を取らないように強制する方法を見つけるのではなく、コードを最も簡単な方法で使用してもらいたい方法を作ります。複数のプログラマーがこのアンチパターンを使用しているという事実は、これに対応するためにライブラリによって提供されるべきライブラリに欠落している部分があると私に思わせます。この必要なコンポーネントの作成をコードのユーザーに押し戻し、彼らが思いついた解決策を好まない.

于 2011-03-16T18:48:29.733 に答える
1

サーバー側がトランスポート構造体を構築するように const 参照の観点からそれらを実装できますが、クライアントの使用はそれらへの const 参照のみが許可され、実際にそれらをインスタンス化または構築して、必要な使用法を強制することはできません。

残念ながら、メッセージ、パッケージング、正しい使用法、および誤った使用法のコード スニペットがなければ、あなたの状況でこれを実装する方法について詳しく説明することはできませんが、不適切な使用を防ぐためにデータ モデルで同様のものを使用しています。また、テンプレート ストレージ クラスをエクスポートして提供し、クライアントが取得したデータを保存したい場合に、クライアントが使用するメッセージからの入力を容易にします。

于 2011-03-16T18:10:45.337 に答える
0

これ以上単純なことは言えません: use protocol buffers . 長期的には、あなたの人生をとても楽にしてくれます。

于 2011-09-02T20:32:49.440 に答える
0

通常、トランスポート メッセージを構造体として定義するのはよくありません。「通常の」(プログラマーにとって便利な)構造体とシリアライザー/デシリアライザーを定義することをお勧めします。シリアライザー/デシリアライザーのコーディングを自動化するには、別のファイルでマクロを使用して構造を定義し、typedef 構造体とシリアライザー/デシリアライザーを自動的に生成することができます (ブースト プリプロセッサ ライブラリも役立つ場合があります)。

于 2011-03-16T18:31:32.213 に答える