時折、エンタープライズ アプリケーション アーキテクチャで継承が「時代遅れ」になっているというコメントに出くわすことがありますが、競合する理論を説明している記事へのリンクは見つけていません。また、ゼロから始めるのではなく、アプリケーションが既に構築されている場合、実装に違いはありますか? これは、代わりにインターフェイスに大きく依存していることと関係があるのではないかと考えていますが、よくわかりません。
7 に答える
あなたは設計原則を参照していると思います:
「継承よりも構成を優先する。」
(サブクラス化の場合のように) 継承に代わる非常に一般的な方法は、オブジェクトの構成と委譲です。
だから代わりに
public class B extends A implements I {
// now I have all the methods from A
}
あなたがやる
public class B implements I {
private I a;
// delegate all methods
public void methodOne(){
a.methodOne();
}
}
コンポジションは、サブクラス化よりも柔軟です。
- 複数のデリゲートを持つことができます (少なくとも Java ではスーパークラスが 1 つだけであるのとは対照的に)。
- インターフェイスを実装から明確に分離します(スーパークラスでは、そのメソッドとその実装の両方を取得し、インターフェイスにないメソッドも取得します)
- 実行時に構成によってデリゲートを交換できます (一方、スーパークラス インスタンスはコンパイルされます)。依存性注入はこれに基づいています。
継承はスタイルではない
それはツールです
コンポジションもそう
このような包括的な手紙を読むたびに、私は自分自身に考えます:
プラスねじはマイナスねじより優れています。
釘や溶接が必要な場合はどちらも役に立たず、自分が何をしているのかわかっている場合は、どちらかまたは両方で問題ありません。
この 2 つの違いは非常に単純で、"is-a" と "has-a" の違いがあります。また、コンポジションを使用して継承をシミュレートすることもできますが (多くの余分な作業が必要です)、逆は一般的に正しくありません。これは継承に反対する議論でもなければ、合成を支持する議論でもありません。
モデルのセマンティクスは、それを表現するために使用されるメカニズムよりもはるかに重要です。「爬虫類は動物の一種である」という代わりに、「爬虫類は動物を持ち、委譲を使用してそのメソッドとプロパティを公開する」と言うのはばかげているでしょう。では、オブジェクトに対して不必要に同じことを行うのは、なぜばかげているだけではないのでしょうか?
継承は非常に便利で、オブジェクト指向プログラミングの基本です。より良いものが登場するまでは消えません。まだ公開していません ;-)
【火をつけよう!】
C ++を使用している場合は、ミックスインの使用を真剣に検討する必要があります(注:他の言語では、何らかの形式のミックスインをサポートしていると主張しています)。
Wikipedia: http://en.wikipedia.org/wiki/Mixin
Dr. Dobbs: http://www.ddj.com/cpp/184404445.
さらに興味深いのは、「不思議なことに繰り返されるテンプレートパターン」(CRTP)です。
Wikipedia: http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern.
CRTPは、非常に便利なミックスインのアプリケーションだと思います。
「理解する」と(これにはしばらく時間がかかります)、ミックスインが非常に強力であることがわかります。これらは、継承による再利用の問題に悩まされることなく、構成や委任を使用するよりも柔軟で効率的なコード再利用の方法を提供します。
興味深いことに、CRTPを使用すると、仮想関数呼び出しをシミュレートして、この言語機能が特に必要とされない実際の仮想関数呼び出しのオーバーヘッド(時間と空間)を取り除くことができます。仮想関数呼び出しを削除すると、コンパイラーはより優れた最適化を提供できるようになり、パフォーマンスが向上します。
利点のリストはどんどん増えていきます...欠点は、C ++では構文的に醜いですが、それと一緒に暮らすことを学びます。マクロを使用してミックスインチェーンを形成すると、コードがはるかに読みやすくなります。
私の見解では、ミックスインは、クラスを構築するために使用できるコードの再利用可能なスニペットとして見ています。通常、これらはインターフェイスの実装を支援し、メソッドの一般的な実装を提供します。あなたは、クラスを構成するビットを「買い物に行く」ことができ、パーツを一緒に機能させるために行う「配管」がほとんどないように感じることになります。
これは、アーキテクチャの問題ではなく、クラスの設計上の重要な問題です。実装の継承には、壊れやすい基本クラスの問題と、継承関係の静的な性質という2 つの困難な領域があります。
この場合の古典的な代替手段は、コンポジションを使用したインターフェイス実装のデコレータ パターンです。新しいオブジェクトには、ラップする下位レベルのオブジェクトへの参照が含まれており、そのオブジェクトへの呼び出しを転送します。おそらく一部の呼び出しは完全にラップまたは置換されます。単一のラッパー クラスは、そのインスタンスがさまざまな基になるサービスの実装をラップすることができます。ラッパーは、保護されたメンバーにアクセスできないため、壊れやすい基本クラスの問題によって壊れる可能性がはるかに低くなります。
Smalltalk と Perl には Traits & Roles もあります。機能を再利用できます。この記事をチェックしてください。