1. ホーム
  2. oop

[解決済み] 継承と集計の比較【終了しました

2022-04-28 19:12:31

質問

オブジェクト指向システムにおいて、コードを拡張、強化、再利用する最善の方法については、2つの考え方があります。

  1. 継承:サブクラスを作成し、クラスの機能を拡張する。スーパークラスのメンバーをサブクラスでオーバーライドし、新しい機能を提供する。スーパークラスが特定のインターフェイスを必要とするが、その実装については不可知論である場合、サブクラスに空白を埋めることを強制するためにメソッドを抽象化/仮想化する。

  2. 集約:他のクラスを取り込み、それらを組み合わせて新しいクラスを作ることで、新しい機能を生み出す。この新しいクラスには、他のコードとの相互運用のために共通のインターフェイスを付けます。

それぞれのメリット、コスト、結果は?他の選択肢はありますか?

この議論は定期的に出てくるのですが、この場で質問されたことはないと思います。 スタックオーバーフローはまだです(関連する議論はあるようですが)。また、Googleの検索結果も意外と少ないです。

どのように解決するのですか?

どれがベストかではなく、いつ何を使うかが問題なのです。

通常のケースでは、簡単な質問で、継承が必要なのか、集約が必要なのかがわかります。

  • もし新しいクラスが 元のクラスと同等かそれ以下であること。継承を使用する。新しいクラスは、元のクラスのサブクラスとなりました。
  • 新しいクラスが 持つ を、元のクラスと比較します。集約を使う。新しいクラスは、メンバーとして元のクラスを持つようになりました。

しかし、大きなグレーゾーンがあります。そこで、他にもいくつかのトリックが必要です。

  • 継承を使った(あるいは使う予定がある)にもかかわらず、インターフェースの一部しか使っていなかったり、相関関係を論理的に保つために多くの機能をオーバーライドせざるを得なかったりする場合です。そうすると、集約を使わざるを得なかったことを示す大きな嫌な臭いがしてきます。
  • アグリゲーションを使った(あるいは使う予定がある)けれども、ほとんどすべての機能をコピーする必要があることがわかった場合。この場合、継承の方向性を示す臭いがします。

端的に言えば 非論理的な状況を避けるために、インターフェースの一部が使用されないか、変更しなければならない場合は集約を使用すべきです。継承を使う必要があるのは、大きな変更をせずにほとんどすべての機能が必要な場合だけです。そして、迷ったら、集約を使う。

もうひとつの可能性は、元のクラスの機能の一部を必要とするクラスがある場合、元のクラスをルートクラスとサブクラスに分割することです。そして、新しいクラスはルートクラスから継承させます。しかし、非論理的な分離をしないように、この点には注意する必要があります。

例を挙げましょう。クラス 'Dog' があり、 'Eat', 'Walk', 'Bark', 'Play' というメソッドを持っています。

class Dog
  Eat;
  Walk;
  Bark;
  Play;
end;

食べる」、「歩く」、「鳴く」、「遊ぶ」を必要とするクラス 'Cat' が必要です。そこで、まずDogから拡張してみましょう。

class Cat is Dog
  Purr; 
end;

見た目はともかく、ちょっと待ってください。この猫は吠えることができるのです(猫好きには殺されそうですが)。そして、吠える猫は宇宙の原理に反している。そこで、Barkメソッドをオーバーライドして、何もしないようにする必要がある。

class Cat is Dog
  Purr; 
  Bark = null;
end;

OK、これは動作しますが、悪い匂いがします。そこで、集約を試してみましょう。

class Cat
  has Dog;
  Eat = Dog.Eat;
  Walk = Dog.Walk;
  Play = Dog.Play;
  Purr;
end;

よし、これはいい。この猫はもう吠えないし、黙ってさえいない。しかし、まだ外に出たがっている内なる犬を持っています。そこで、3番目の解決策を試してみましょう。

class Pet
  Eat;
  Walk;
  Play;
end;

class Dog is Pet
  Bark;
end;

class Cat is Pet
  Purr;
end;

この方がずっとすっきりしています。内部の犬がいません。そして、猫と犬は同じレベルです。他のペットを導入してモデルを拡張することも可能です。魚や、歩かないものでなければ。その場合はまたリファクタリングが必要です。しかし、それはまた別の機会に。