構成の簡単なコード例についての回答を探していました。構成と継承の違いは知っていますが、コードを使用して理解することはできません。
構成を使用する必要がある理由に関する比較ベースの例 (両方のアプローチを使用) は非常に役立ちます。
前もって感謝します
構成の簡単なコード例についての回答を探していました。構成と継承の違いは知っていますが、コードを使用して理解することはできません。
構成を使用する必要がある理由に関する比較ベースの例 (両方のアプローチを使用) は非常に役立ちます。
前もって感謝します
基本的な違いは、継承がコンパイル時にクラス階層を修正するのに対し、合成では実行時に合成されたクラスの関係を決定できることです。
継承で、継承階層でコードを固定しました。たとえば、 Circle
クラスからShape
クラスを継承する場合、クラスShape
の基底クラスとして固定されCircle
ます。
Shape を2DShape
、 、 とさらに分類するとし3DShape
ます。Circle
継承により、クラスが から継承することはできなくなりました2DShape
。
コンポジションなら可能です。したがって、構成されたクラスを、実行時に構成されたクラスの派生型のいずれかに変更できます。
おそらく、継承よりも合成をチェックしたいかもしれません
継承よりも構成を優先することは、設計の柔軟性を高め、ビジネス ドメイン クラスと長期的に安定したビジネス ドメインを提供する設計原則です。つまり、HAS-A は IS-A 関係よりも優れている可能性があります。
コード例との違いを説明している関連投稿でaleembの回答を確認してください
これは、継承よりも構成を好む理由を説明する便利なリンクです
構成と継承の両方でコードを再利用できますが、継承の欠点の 1 つは、カプセル化が壊れることです。サブクラスがその動作をスーパークラスの振る舞いに依存していると、突然壊れやすくなります。スーパー クラスの動作が変更されると、サブ クラスの機能が壊れる可能性があります。コードを脆弱にする継承の一例は、HashSet のメソッド add() と addAll() です。HashSet の addAll() が add() メソッドを呼び出して実装されている場合、HashSet のサブクラスを記述して、HashSet に挿入する前にコンテンツを暗号化するとします。オブジェクトを HashSet に挿入できるメソッド add() は 1 つしかないため、これらのメソッドをオーバーライドし、add() をオーバーライドして encrypt() メソッドを呼び出します。addAll() は add() を使用して実装されているため、これは自動的に addAll() もカバーします。非常に魅力的に見えます。よく見ると、スーパークラスの動作に依存しているため、この実装が脆弱であることがわかります。基本クラスがパフォーマンスを向上させ、add() メソッドを呼び出さずに addAll() を実装する場合、以下の例は壊れます。
public class EncryptedHashSet extends HashSet{
.....
public boolean add(Object o) {
return super.add(encrypt(o));
}
}
継承を支持してコンポジションを使用した場合、この問題に直面することはなく、スーパークラスの動作に依存しなくなるため、クラスはより堅牢になります。代わりに、追加部分にスーパークラスメソッドを使用しているため、以下の例に示すように、 addAll() の改善によりメリットが得られます。
public class EncryptedHashSet implements Set{
private HashSet container;
public boolean add(Object o) {
return container.add(encrypt(o));
}
public boolean addAll(Collection c) {
return conatainer.add(encrypt(c));
}
.......
}
Joshua Bloch が最もよく言っていると思います:項目 16: 継承よりも構成を優先する