1

これは私の最初の質問です:)

オブジェクト タイプをチェックするのではなく、代わりに dynamic_cast を使用する必要があることはわかっていますが、それでは問題は解決しません。

Extension というクラスと、IExtendable および IInitializable、IUpdatable、ILoadable、IDrawable というインターフェイスがあります (最後の 4 つは基本的に同じです)。Extension が IExtendable インターフェイスを実装している場合、さまざまな Extension オブジェクトで拡張できます。

問題は、IExtendable を実装する Extension を、元の Extension と同じインターフェイスを実装する Extension でのみ拡張できるようにしたいことです。

あなたはおそらくその混乱を理解していないので、コードで説明しようとします:

class IExtendable
{
public:
 IExtendable(void);

 void AddExtension(Extension*);
 void RemoveExtensionByID(unsigned int);

 vector<Extension*>* GetExtensionPtr(){return &extensions;};
private:
 vector<Extension*> extensions;
};

class IUpdatable
{
public:
 IUpdatable(void);
 ~IUpdatable(void);

 virtual void Update();
};

class Extension
{
public:
 Extension(void);
 virtual ~Extension(void);

 void Enable(){enabled=true;};
 void Disable(){enabled=false;};

 unsigned int GetIndex(){return ID;};

private:
 bool enabled;
 unsigned int ID;

 static unsigned int _indexID;
};

次に、次のような拡張機能を作成する場合を想像してください。

class MyExtension : public Extension, public IExtendable, public IUpdatable, public IDrawable
{
public:
    MyExtension(void);
    virtual ~MyExtension(void);

    virtual void AddExtension(Extension*);
    virtual void Update();
    virtual void Draw();
};

そして、このクラスが同じ (またはそれ以下の) インターフェースを実装する拡張機能でのみ拡張できるようにしたいと考えています。たとえば、IUpdatable を実装する Extension を使用できるようにしたいと考えています。または IUpdatable と IDrawable の両方。しかし、例えば、ILoadable を実装する Extension ではありません。たとえば、IExtendable と IUpdateable を実装する拡張機能で Update() が呼び出されると、この拡張機能を拡張するこれらの拡張機能でも呼び出されるため、これを行います。

したがって、IExtendable と IUpdatable、ILoadable の一部を実装する Extension に Extension を追加するときは、追加する Extension がこれらのインターフェイスも実装しているかどうかを確認する必要があります。したがって、 IExtendable::AddExtension(Extension*) では、次のようにする必要があります。

void IExtendable::AddExtension(Extension* pEx)
{
bool ok = true;
// check wheather this extension can take pEx
// do this with every interface
if ((*pEx is IUpdatable) && (*this is_not IUpdatable))
ok = false;

if (ok) this->extensions.push_back(pEx);

}

しかし、どのように?最善の解決策は何ですか?dynamic_cast を使用したくなくて、それが null を返すかどうかを確認したくありません... ありがとう

4

3 に答える 3

6

設計を再考する必要があります。この動作が必要な場合は、おそらく と を導入IUpdateExtendableしてIDrawExtendableください。

現在のアプローチが悪い理由は、リスコフの置換原理に違反しているためです。あなたは基本的に、「このオブジェクトは IExtendable として機能しますが、実際には機能しません。..」と言っているのです。そうでない場合は、メンテナンスの悪夢が待っています。

于 2010-03-27T18:32:58.070 に答える
0

単なる直感ですが、拡張機能が何をしているかによっては、ビジターパターンが役立つ場合があります。デコレータパターンについても読むことをお勧めします。

于 2010-03-27T18:38:47.227 に答える
0

これらすべてのインターフェイスを 1 つのクラスにマージできるので、次のようになります。

class Extension
{
public:
Extension(void);
virtual ~Extension(void);

void AddExtension(Extension* pEx){extensions.push_back(pEx);};

virtual void Initialize()
{
for each (Extension* pEx in extensions) pEx->Initialize();
};

virtual void Load()
{
for each (Extension* pEx in extensions) pEx->Load();
};

virtual void Update()
{
for each (Extension* pEx in extensions) pEx->Update();
};

virtual void Draw()
{
for each (Extension* pEx in extensions) pEx->Draw();
};

private:
vector<Extension*> extensions;
};

ただし、これは、追加されたすべての拡張機能ですべてのメソッドが呼び出されることを意味します。たとえば、コンテンツをロードせず、何も描画しない、追加された拡張機能の空のメソッドが呼び出されます。

于 2010-03-27T21:38:37.490 に答える