すべてをしっかりと理解するために、一般的なオブジェクト指向の概念についての本を読んでいます。私を失望させているのは、継承と構成の違いです。継承に関しては、サブクラスとの「is-a」であることを知っています。 Employeeクラスなどは、Personクラスを継承しています。コンポジションのサブクラスは「has-a」です。たとえば、車にはハンドルがあるため、CarクラスはSteering Wheelクラスから継承します。
これまでのところ、クール。しかし...これはまだ継承ではありませんか? 「is-a」と「has-a」の違いを理解しています。また、Compositionは基本的に複数のクラスを組み合わせて、それらすべてのオブジェクトを含む別のクラスを作成することも理解しています。 2つの質問があります。
私はその違いをよく理解しており、自分のプログラムを通じてそれぞれの使い方を知っています。合成が本当に継承の形式であるかどうかは、セマンティクスに関する質問にすぎないと思います。
いいえ、2つの概念は異なります。
より良い車のアナロジーは、エンジンに関してでしょう。エンジンのインターフェースがあるとしましょう。シリンダー数やRPMなどのプロパティがある場合があります。スロットルの開閉などの動作を呼び出すことができる場合があります。ただし、これは単なるインターフェースであり、エンジンは実装ではありません。 Carクラスにはエンジンがあります。車を作成するときに、そのエンジンインターフェイスを実装するsomethingをインストールします。多くの車はオプションとして異なるエンジンを持っています。
今、実装があります。おそらく、SixCylinderEngine
クラスを定義します。それはそのインターフェースを実装しているのでエンジンです。エンジンインターフェイスが使用されている場所ならどこでも使用できます。
ちょっと待って! スーパーチャージバージョンのエンジンが必要な人もいます。これは、既存のエンジンの変数を変更するほど簡単ではありません。これは大きな変更です。さまざまなパーツ、2番目のドライブベルト、別の主要コンポーネント(過給機)、より多くの馬力など。
これを達成する1つの方法は、SixCylinderEngine
をサブクラス化し、スーパーチャージャーに追加することです。これにはメリットがありますが、サブクラスとスーパークラスの間に複雑な相互依存関係が生じる可能性があります。それはもう1つの関係です。
代わりに、エンジンを直接実装するSuperchargedSixCylinderEngine
クラスを定義します(is-a)。コードを再利用するために、内部にはSixCylinderEngine
とdelegates特定の関数(has-a)が含まれています。
ここから、次のステップはanyエンジンを受け入れるSuperchargedEngine
を用意することです:6、8、10シリンダー、必要なものは何でも。
これが違いのコード例です。
継承:
public int getHorsepower() {
return 1.4 * super.getHorsepower();
}
組成:
private Engine engine;
public SuperchargedEngine(Engine e) {
engine = e;
}
public int getHorsepower() {
return 1.4 * engine.getHorsepower();
}