[解決済み] 継承と集計の比較【終了しました
質問
オブジェクト指向システムにおいて、コードを拡張、強化、再利用する最善の方法については、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;
この方がずっとすっきりしています。内部の犬がいません。そして、猫と犬は同じレベルです。他のペットを導入してモデルを拡張することも可能です。魚や、歩かないものでなければ。その場合はまたリファクタリングが必要です。しかし、それはまた別の機会に。
関連
-
[解決済み] 私的相続、公的相続、保護相続の違いについて
-
[解決済み] インターフェースとベースクラス
-
[解決済み] コヒーシ ョンとカップリングの違い
-
[解決済み】AngularJSのスコーププロトタイピング/プロトタイピング継承のニュアンスとは?
-
[解決済み】プロトタイプ継承の利点は古典的なものよりも?
-
[解決済み】継承と合成の違いについて
-
[解決済み] Delegateとは?[クローズド]。
-
[解決済み] プライベートとプロテクト-ビジビリティ・グッド・プラクティスの懸念点【終了しました
-
[解決済み] 継承と集計の比較【終了しました
-
[解決済み] nullを返すのは設計ミス?[クローズド]
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 抽象メソッドと仮想メソッドの違いは何ですか?
-
[解決済み] インターフェースと抽象クラス(一般的なOO)
-
[解決済み] ポリモーフィズムとは何か、何のためにあり、どのように使われるのか?
-
[解決済み] 抽象クラスの代わりにインターフェイスを使用する場合とその逆は?
-
[解決済み】コンストラクターとファクトリーメソッドの比較【終了しました
-
[解決済み] テンプレート方式とストラテジーパターンの違いは何ですか?
-
[解決済み] ミュータブルとイミュータブルのオブジェクト
-
[解決済み] ProxyパターンとDecoratorパターンの違い
-
[解決済み] コンストラクタをprivateにするとどうなるのですか?
-
[解決済み] nullを返すのは設計ミス?[クローズド]