構成と継承

すべての開発者と同様に、「構成は常に継承よりも優れている」という声明を読んで聞く必要がありました。 おそらくあまりにも頻繁に。 しかし、私は信仰について何も考えたくないので、そうであるかどうかを考えましょう。





それでは、継承よりも合成の利点は何ですか?



1.継承で可能な名前の競合はありません。

2.実行時に集約オブジェクトを変更する機能。

3.集約オブジェクトを含むクラスから派生したクラスの集約オブジェクトの完全な置換。



最後の2つのケースでは、交換可能な集約オブジェクトに共通のインターフェースがあることが非常に望ましいです。 そして3番目-そのようなオブジェクトを返すメソッドが仮想であるように。



たとえば、複数の継承をサポートしていないが、複数のインターフェイスから継承してこれらのインターフェイスの拡張メソッドを作成できるC#を考慮すると、さらに2つの利点があります(この場合、「戦略」パターンのフレームワークでの動作アルゴリズム )についてのみ話すことができます ) "):

4.集約された動作(アルゴリズム)には他のオブジェクトが含まれる場合があります。 特に、集約により他の動作を再利用できます。

5.集約中、コンストラクターに渡すことにより、実装の特定の部分と動作に必要な初期パラメーターを非表示にすることができます(継承中、動作は独自のインターフェイスのメソッド/プロパティを介して要求する必要があります)。



しかし、短所はどうですか? 本当になくなったのですか?



1.したがって、外部から動作を変更する機能が必要な場合、構成は、継承と比較して、動作のオブジェクトとそれを使用するオブジェクトとの間に根本的に異なるタイプの関係を持ちます。 抽象的な振る舞いから継承する場合、1:1の比率があり、集約と外部からの振る舞いを設定する可能性があるため、1:多くの比率が得られます。 つまり 同じ動作オブジェクトを複数の所有者オブジェクトで使用できます。 これにより、これらの所有者オブジェクトのいくつかの一般的な動作状態に問題が発生します。



この状況は、外部からの動作のインストールを禁止するか、たとえば汎用メソッドに委任することで解決できます。
void SetBehavior<TBehavior>()
      
      



これにより、所有者オブジェクト以外のユーザーによる動作の作成が禁止されます。 ただし、「他の場所」での動作の使用を禁止することはできません。 ガベージコレクター(GC)のない言語では、これは理解できる問題を引き起こします。 もちろん、このような言語では、所有者オブジェクト自体を違法に参照することもできますが、分離された動作オブジェクトを左右に分散させることで、例外を取得する機会が何度も得られます。



2.集約(およびこれが主なニュアンス)は、集約オブジェクトが所有者オブジェクトではなく、それに関する情報を含まないという点で、第一に継承と異なります。 ビヘイビアーとやり取りするコードが所有者オブジェクト自体を必要とする場合がよくあります(たとえば、所有する他のビヘイビアーに関する情報を取得するため)。



この場合、型指定されていないオブジェクト(オブジェクトやvoid *など)をコードに渡すか、所有者オブジェクトの追加インターフェイス(一部のIBehaviorOwner)を作成するか、ビヘイビアーの所有者オブジェクトへの循環参照を保存する必要があります。 これらの各オプションには欠点があり、コードがさらに複雑になることは明らかです。 さらに、異なるタイプの動作は互いに依存する可能性があります(特に、ある種の閉じられた自己完結型モジュールにある場合、これは完全に受け入れられます)。



3.さて、最後のマイナスはもちろんパフォーマンスです。 多くのオブジェクト所有者がいる場合、1つのオブジェクトではなく2つ以上のオブジェクトの作成と破棄が見過ごされることはありません。



「構成は常に継承よりも優れている」というステートメントは、物議を醸すものであり、教義であってはならないことが判明しています。 これは、多重継承を許可し、GCを持たない言語に特に当てはまります。 いずれの状況でも上記の利点が重要ではなく、特定のタイプを使用するときに使用できないことが事前にわかっている場合、継承のオプションを検討する必要があります。



All Articles