0

私のシステムでは、プラグイン プログラマーが、データ ストレージとして使用されるクラス A の複数のインスタンスを作成できます。

class A
{
protected:
    int val;
public:
    A( int v ) : val(v)
    { 
        GlobalList::register(this);
    }
    int get() { return val; }
};

私は今、そのようなオブジェクトにいくつかの「ビュー」を持つ必要があります。つまり、A へのアクセサ関数を持つ必要があるさまざまなモジュールがあり、他のモジュールには表示されません。1 つのケースとして、オブジェクトを作成するプラグイン プログラマーはゲッターのみを参照する必要があります。ただし、A レジスター自体がグローバルな静的リスト クラスであり、時々アクセスしてその値を変更するメカニズムを使用します。

私の質問は、これを適切に設計する方法です。通常、これを解決するには、A をいくつかの抽象インターフェイスから派生させて実装し、各モジュールに A へのカスタムの制限されたインターフェイス ポインターのみを与えます。ただし、プラグイン プログラマーがオブジェクトをインスタンス化してアクセスできるため、これはできません。とにかくすべてのパブリック関数に。

次の 2 つのオプションが考えられます。

1) プライベートな change() メソッドを A に追加し、GlobalList に A* のリストを与え、GlobalList を A のフレンドにします。その後、GlobalList は A::change を呼び出すことができますが、ユーザーは呼び出すことができません。ただし、A にカスタムの「ビュー」を持つクラスを追加するたびに、フレンド リストを拡張する必要があります。これは、A のクラス定義を常に変更する必要があるため、最適な設計とは言えません。

2) A の「ビュー」ごとに、A から派生し、change() メソッドを持つある種のアクセサ クラスを作成します。次に、GlobalList に Accessor* のリストを指定します。A のインスタンスを GlobalList クラスに登録するときは、次のように、インスタンスへのポインターをアクセサー関数のポインターにキャストします。

class A
{
protected:
    int val;
public:
    A( int v ) { val = v; }
    int get() { return val; }
};


class AccessorA : public A
{
public:
    void change( int v ) { val = v; }
};

GlobalList::register( A* obj )
{
    mlist.push_back( (AccessorA*) obj );
}

次に、GlobalList は、A の変更機能を提供するポインターのリストを反復処理できます。A を作成したユーザーは、(アクセスできないプライベートであっても) change() メソッドを見ることはなく、A のクラス定義は、 A のビューを持つ GlobalList のような新しいクラスを追加しても、変更されました。

2 番目の方法はうまくいき、なんとなくきれいに見えますが、私には奇妙に見えます。この設計が劇的に失敗する致命的なケースを見逃しているという悪い予感がします。(特に: そんなに簡単なら、誰もが A から派生し、そのポインタを再解釈して、操作できる... ?)

誰かが私にアドバイスをくれますか?2 番目の方法は、既知のパターンに関連していますか? または、これを解決するための、より優れた、よりクリーンで、より堅牢な方法がありますか?

ご提案ありがとうございます。

4

1 に答える 1

0

2 つのオプションから選択すると、「フレンド」オプションを選択します。追加のコード行を何行も必要とせず、ロジックが圧縮され (2 つの別々のクラスに分割されない)、ニーズを満たすためです。

ただし、多態的なソリューションを実装して、プラグイン ユーザーから不要なコードを「隠す」ことができます。

したがって、私の解決策は、これら2つの混合物になる可能性があります。

class A_base
{
  friend class GlobalList;

public:
   A_base(int v) : val(v) {}

   int get() { return val; }

private:
   int v;

   void set(int v) { val = v; }
};

class A : public A_base
{
public:
   A(int v) : A_base(v)
   {
      GlobalList::register(this);
   }
};

(または同様の)のGlobalListリストが必要です。A *

GlobalListアクセスのために、すべてAA_baseメソッドとフィールド、、publicおよびprotectedものprivateに直接アクセスできるため、必要に応じfriend classて変更できvalます。プラグイン ユーザーはクラスをインスタンス化する必要があり、 との部分にAのみアクセスできるため、整合性が維持されます。publicAA_base

于 2013-07-14T18:49:30.373 に答える