GUI コンポーネントの階層のルートである Component という抽象基本クラスがあるとします。このような場合、Button と Label の 2 つのサブクラスがあり、どちらも抽象クラスであり、具象クラスのそれぞれの階層のルートとして存在します。
Button から継承する具象クラスには、RoundButton および SquareButton が含まれる場合があります。
Label から継承する具体的なクラスには、TextLabel と PictureLabel が含まれる場合があります。
最後に、Component オブジェクトのコレクションを保持する集約 Container クラスがあるとします。
問題は、コンポーネント オブジェクトへのポインターがあることですが、それらがボタンまたはラベルのいずれかであることを識別する必要があります。たとえば、すべてのボタンの内部テキストに大きなフォントを使用するように指定したい場合、コンテナ内のすべてのコンポーネント オブジェクトを反復処理して、どのボタンがボタンであるかを何らかの方法で特定し、ボタン固有のメソッドを呼び出すことができます。
これらのコンポーネント「ファミリ」が自身を識別する 1 つの方法は、文字列を使用することです。
class Component {
public:
virtual char const * const getFamilyID() const = 0;
};
// In Button.h
char const * const COMPONENT_BUTTON = "button";
class Button : public Component {
public:
virtual char const * const getFamilyID() const { return COMPONENT_BUTTON; };
};
// Code sample
if (strcmp(component->getFamilyID(),COMPONENT_BUTTON) == 0)
// It's a button!
これは、コンポーネントがこれらのファミリを定義するタスクをその子に任せているという点で疎結合です。どのファミリが存在するかを知る必要はありません。クライアントはさまざまなコンポーネント ファミリを認識している必要がありますが、何らかの操作で特定のコンポーネント ファミリをターゲットにしようとしている場合、それは避けられません。
ただし、非常に高いパフォーマンス要件があり、文字列の比較を避けたいとします。また、インライン化できるように、この関数を仮想化することは避けたほうがよいでしょう。また、Component のすべてのサブクラスがグローバル定数を宣言する必要がある場合は、何らかの方法で Component クラスを変更して、これを要件にするか不要にするのがよいでしょう。
この問題の解決策の 1 つは、Component.h で列挙子を定義することです。
enum COMPONENT_FAMILY {
COMPONENT_BUTTON = 0,
COMPONENT_LABEL,
// etc...
};
この場合、 getFamilyID() は COMPONENT_FAMILY 列挙型を返すだけでよく、基本的には int を比較するだけです。残念ながら、これは、新しいコンポーネント ファミリをこの列挙型に「登録」する必要があることを意味します。これは簡単ですが、他のプログラマにとって完全に直感的ではありません。また、カーディナリティが非常に低い (理想的ではない) ことがわかっている非静的 COMPONENT_FAMILY メンバーを作成しない限り、メソッドは依然として仮想である必要があります。
この問題を解決する良い方法は何でしょうか? 私の場合、パフォーマンスが重要であり、enum ソリューションに似たもので十分に簡単に思えますが、より良い方法を見落としているのではないかと考えています。
--- 編集 ---
実際のシステムでは、同等のコンテナは各ファミリから 1 つのコンポーネントしか保存できないことをおそらく指摘する必要があることを認識しています。したがって、コンポーネントは実際には次のようなマップに格納されます。
std:map<COMPONENT_FAMILY, Component*>
ここでの私の簡単な例に当てはめると、これはコンテナに 1 つのボタン、1 つのラベルなどしか含めることができないことを意味します。
これにより、特定のタイプのコンポーネント (ログ時間) の存在を簡単に確認できます。したがって、この質問は、COMPONENT_FAMILY を表す方法と、コンポーネントをマップに追加するときにコンポーネントのタイプを決定する方法に関するものです。
つまり、コンポーネントの唯一の目的は、コンテナに追加された特定の機能として識別され、すべてのコンポーネントが一緒になってコンテナの特定の動作を定義することです。
したがって、コンポーネントのタイプを知る必要はありません。それは既に暗示されています。具体的には、コンテナに特定のタイプのコンポーネントを要求しています。私が必要としているのは、最初にマッピングできるように、コンポーネントがそのタイプを伝達する方法です。