2016-05-05 6 views
4

クラスと型でこのような問題を解決するにはどうすればよいでしょうか?ここ は、私はこのインタフェースは、具体的な実装についてのアイデアを持っていないライブラリの内部で使用されているすべてのもの仮想メソッドを使用したクラスの設計

class IWindow 
    { 
    public: 
     virtual void Refresh() = 0; 
// another 100 virtual methods 
// ... 
    }; 

ため

ベースのインタフェースを持っているものです。ここで

は今、私たちはいくつかの追加のメソッドを追加し、また、そのライブラリの内部で使用される別のインタフェースを持っている具体的な実装

class ConcreteWindow : public IWindow 
    { 
    public: 
     void Refresh() override {} 
/// the other 100 overridden methods 
    }; 

のバージョンです。

class IDBDetail : public IWindow 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 

とここでの主な問題であり、私たちはもちろんのこと

class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow 
{ 
public : 
    void DoDetail() {} 
}; 

ための具体的なinmplementationを作成するとき、それはそれらの100個のメソッドを実装していないので、具体的なクラスIGDBDetailWrapperが同様に抽象的ですが、私はそれをやりたいとは思わないが、実装をConcreteWindowから再利用したいのですが、それらはすべて同じウィンドウハンドルで作業していますが、これはもちろんコンパイルされません。

私は IGDBDetailWrapperConcreteWindowからそれらの100個のメソッドをコピー/ペーストすることができますが、私は別の10のなど新しいインターフェースや具体的な実装を持っているかもしれない原因それは、やり過ぎだ

質問を解決し、これらの100のメソッドを何度も何度も何度もやり直すのに役立つ他のパターンはここで使用できますか?

Thxを

+2

からあなたの101抽象メソッドの実装を使用しますそれは間違っている。純粋なインターフェイスは、それがいくつかの機能以上のものを持っている場合、かなり退屈になります。しかし、悪化すると、デバッグが非常に難しくなります。ただしないで、 "ウィンドウ"は実用的なベースクラスを必要とします。他の人がどのようにこれを行い、GUIラッパーライブラリがたくさんあるかを見てください。 –

+0

なぜConcreteWindowから継承しないのですか? –

+0

基本クラスの100個のメソッドがひどく、 'IDBDetail'と' IWindow'の間の継承関係が間違っているので、ライブラリの設計が悪いだけです。あなたはきれいな解決策を見つけることはできません。このライブラリの任意のクライアントは、1つの回避策または他の回避策を使用する必要があります。 –

答えて

2

仮想継承を使用できます。私たちは、実際にはIDBDetailIWindowから継承するかべきではありません無視した場合、我々は現在のアーキテクチャの問題を解決するために、仮想継承を使用することができます。

class IWindow 
    { 
    public: 
     virtual void Refresh() = 0; 
// another 100 virtual methods 
// ... 
    }; 

    class ConcreteWindow : virtual public IWindow 
    { 
    public: 
     void Refresh() override {} 
/// the other 100 overridden methods 
    }; 

class IDBDetail : virtual public IWindow 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 

class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow 
{ 
public : 
    void DoDetail() {} 
}; 

今、コンパイラはあなただけやっているConcreteWindow

+0

どうも! – Eugen

4

あなたのデザインがdiamond problemに実行されています。

ここでは、いくつかの追加メソッドを追加し、そのライブラリ内でも も使用する別のインターフェイスがあります。

class IDBDetail : public IWindow { 
    public: 
    virtual void DoDetail() = 0; 

}; 

あなたIDBDetailインターフェイスの説明からIDBDetailはIWindowから継承するべきではないように見えます。追加機能を追加するだけの場合、IDBDetailはIWindowである必要はありません。 IWindowを理解するだけです。例えば、サルに特別なことをさせるために、トレーナーはサルである必要はありません。

Decorator patternがあなたが探しているものかもしれません。

+1

これは動作しません。そのライブラリの内部でメソッドがIDBDetailへのポインタを使用して、IWindowからメソッドにアクセスします。残念ながらそのライブラリを変更する方法はありません。 – Eugen

+0

@Eugen Ok。しかし、もしあなたがあなたの質問の中の一つの選択肢をすれば、現在の継承モデルには行くことができません。ダイヤモンドの問題 – bashrc

2

抽象クラスのすべてのメソッドをオーバーライドする必要がありますが、それ以外の方法はありません。実際には、ここで100のメソッドの抽象クラスを作成すべきではありません。おそらく、それをいくつかのより小さな抽象クラスで分けることができますか?しかし、この場合、IDBDetailはIWindowの後に継承してはならず、IGBDDetailWrapperもIWindowの後に継承すべきではありません。Visual Studioを使用している場合は

+0

おそらくもっと小さなクラスに分割すると助けになるかもしれません。私はこれをチェックしなければならないだろう。 – Eugen

3

まず、そうでなければ二退屈な作業、何ができるか自動化のお手伝いをすることができますリファクタリングツールがあります。私には

は同じことをやってずっと無意味です:

class IDBDetail : public IWindow 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 
私が代わりに

class IDBDetail 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 

インターフェースはとてもメートルの、既に何百とのインタフェースを乱雑に、抽象化の責任に使用されるべきであることだろう

付加的な方法を用いたエドモンドは、悪いデザインの兆候です。あなたが任意の派生ですることができます後で再利用その

class IDBDetailWithConcreteWindow: public IDBDetail{ 

    IWindow * concreteWindow; 
public: 
    IDBDetailWithConcreteWindow(IWindow * window){ 
     concreteWindow = window; 
    } 

    void Refresh() override{ 
     concreteWindow->Refresh(); 
    } 
} 

そして最後に、あなたが時間、あなたのための問題を解決するクラスを作成しますので、すべてのための組成物を一時間を活用し、可能性が

あなたはこのソリューションの利点があれば、あなたが悪いデザイン性などの外部制約を(持っているということですIDBDetail

IGDBDetailWrapper: public IDBDetailWithConcreteWindow{ 
public: 

    void DoDetail() override { } 
} 

からメソッドを実装する必要があり、クラスIDBDetailインターフェイスを変更できない場合、上位ソリューションは機能しません。

2

それはあなたの問題を解決することはできませんが、少なくとも、あなたは実行を自分でリダイレクトすることができますあなたが望むよう

class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow 
{ 
public: 
    virtual void DoDetail() override { /*work here*/ } 

    virtual void Refresh() override { ConcreteWindow::Refresh(); } 
    //another 100 methods 
}; 

あなたは何度でもコンパイラ#DEFINEようなリダイレクションのブロックを作り、それを繰り返すことができます。

+0

@DarioOOは、リダイレクトを自動的に作成するために「Visual Studioリファクタリングツール」を使用できると述べています。この問題を解決した –

3

@bashrcは正しいですが、仮想継承の問題を解決することが可能でなければなりません:

class ConcreteWindow : public virtual IWindow {...} 

class IDBDetail : public virtual IWindow {...} 

このWikipediaの記事virtual inheritanceの状態ソリューションとしても。

関連する問題