コンピュータサイエンスでは、オブジェクト合成とオブジェクト集約は、オブジェクトやデータ型を組み合わせてより複雑なものにするための密接に関連した方法です。会話では、合成と集約の区別はしばしば無視されます。[ 1 ]一般的な合成の種類としては、オブジェクト指向プログラミングで使用されるオブジェクト、 タグ付き共用体、セット、シーケンス、およびさまざまなグラフ構造があります。オブジェクト合成はデータ構造と関連していますが、同じではありません。
オブジェクト構成とは、情報の論理的または概念的な構造を指し、それを表現するために用いられる実装や物理的なデータ構造を指すものではありません。例えば、シーケンスはセットとは異なり、(とりわけ)前者では構成要素の順序が重要になりますが、後者では重要ではありません。配列、リンクリスト、ハッシュテーブルなどのデータ構造は、どちらを実装するためにも使用できます。紛らわしいことに、データ構造とコンポジットの両方に同じ用語が使われることがあります。例えば、「バイナリツリー」はどちらを指す場合もあります。データ構造としては、項目の線形シーケンスにアクセスする手段であり、ツリー内の項目の実際の位置は関係ありません(ツリーは、意味を変えることなく、内部的に好きなように再配置できます)。しかし、オブジェクト構成としては、位置は重要であり、位置を変更すると意味が変わります(例えば、系統樹など)。
オブジェクト指向プログラミングは、オブジェクトを使用してデータと動作をカプセル化することに基づいています。機能をより複雑なものに組み立てて構成するために、サブタイピングとオブジェクト合成という 2 つの主要な手法を使用します。 [ 2 ]オブジェクト合成とは、複合オブジェクト内でオブジェクトを組み合わせ、同時に、内部構造が見えないように明確に定義されたインターフェースを使用することで、各オブジェクトのカプセル化を保証する ことです。この点で、オブジェクト合成は、カプセル化を強制しないデータ構造とは異なります。
オブジェクトの構成は、オブジェクトのセットやシーケンスなど、複数の関連オブジェクトのグループに関する場合もあります。委譲は、囲んでいる複合オブジェクトに対して行われた要求や呼び出しをその内部コンポーネントのいずれかに転送することで、構成を豊かにすることができます。[ 3 ]
クラスベースおよび型付きプログラミング言語では、型は複合型と非複合型に分類でき、合成は型間の関係とみなすことができます。複合型のオブジェクト (例: car )は、他の型のオブジェクト (例: wheel ) を「持つ」ことができます。複合オブジェクトが同じ型の複数のサブオブジェクトを含む場合、それらは特定の役割に割り当てられることがあり、多くの場合、名前または番号で区別されます。たとえば、Pointオブジェクトには、それぞれ「x」、「y」、「z」などの異なる軸に沿った距離を表す 3 つの数値が含まれる場合があります。一般的に、部分と全体の関係の研究は、部分論です。
コンポジションは、サブタイピングとは区別されるべきである。サブタイピングとは、一般的なデータ型に詳細を追加して、より具体的なデータ型を作成するプロセスである。例えば、車は特定の種類の乗り物である。つまり、車は乗り物である 。サブタイピングは、異なるオブジェクト間の関係を記述するのではなく、ある型のオブジェクトが同時に別の型のオブジェクトでもあることを示す。このような関係を研究するのがオントロジーである。
JavaScriptのようなプロトタイプベースのプログラミング言語では、オブジェクトはインスタンス化される瞬間にプロトタイプオブジェクトから動作を動的に継承できます。コンポジションはプロトタイピングとは区別されるべきです。新しくインスタンス化されたオブジェクトはプロトタイプのコンポジションを継承しますが、それ自体が独自にコンポジションを持つことも可能だからです。
複合オブジェクトは、構成オブジェクトを同じ場所に配置する、参照を同じ場所に配置する、またはその他のさまざまな方法でストレージに表現できます。複合オブジェクト内の項目は、属性、フィールド、メンバー、プロパティ、またはその他の名前で参照でき、結果として得られる構成は、複合型、ストレージレコード、構造、タプル、またはユーザー定義型 (UDT)として参照できます。詳細については、以下の集約のセクションを参照してください。

UMLモデリングでは、オブジェクトはプログラミング言語による実装とは独立して概念的に構成できます。UML でオブジェクトを構成する方法は、プロパティ、関連、集約、構成の 4 つあります。[ 4 ]
集約とその構成要素間の関係は弱い「has-a」関係です。構成要素は複数の集約の一部になる可能性があり、集約を経由せずに他のオブジェクトからアクセスされる可能性があり、集約オブジェクトよりも長く存続する可能性があります。[ 4 ]構成要素オブジェクトの状態は、依然として集約オブジェクトの一部を形成します。
複合体とその構成要素との関係は、強い「has-a」関係です。複合体オブジェクトは「構成要素オブジェクトの存在と格納に対する責任」を単独で持ち、構成要素オブジェクトは最大で1つの複合体の一部になることができ、「複合体オブジェクトが削除されると、その構成要素であるオブジェクトもすべて一緒に削除されます」。したがって、UMLにおけるコンポジションは、通常のオブジェクト構成よりも狭い意味を持ちます。

この図式表記は以下を表しています。
集約は、所有権を伴わないという点で、通常の構成とは異なります。構成では、所有するオブジェクトが破壊されると、その中に含まれるオブジェクトも破壊されます。しかし、集約では必ずしもそうではありません。例えば、大学は様々な学部(例えば化学科)を所有しており、各学部には複数の教授がいます。大学が閉鎖されると、学部は存在しなくなりますが、それらの学部に所属する教授は存続します。したがって、大学は学部の集合体と見なすことができ、学部は教授の集合体と見なすことができます。さらに、教授は複数の学部に所属できますが、学部は複数の大学に属することはできません。
コンポジションは通常、あるオブジェクトが別のオブジェクトを含むように実装されます。例えば、C++では次のようになります。
import std ;using std :: string ; using std :: vector ; using std :: weak_ptr ;class Professor { // ... };class Department { private : // 集約: 教授は学科よりも長く存続する可能性があります。vector < weak_ptr < Professor >> members ; const string title ; public : explicit Department ( const string & title ) : title { title } {} };class University { private : // コンポジション: 学部は教員が存在する限り存在します。vector < Department > faculty = { Department ( "Chemistry" ), Department ( "Physics" ), Department ( "Arts" ), // ここにさらに学部を追加... }; public : University () = default ; };集約においては、オブジェクトはオブジェクトへの参照またはポインタのみを含み(そのオブジェクトに対する生涯責任を負わない)、
通常の合成と集約の区別が重要でない場合、集約は合成と呼ばれることがある。
上記のコードは、以下のUMLクラス図に変換されます。


Microsoft のコンポーネント オブジェクト モデルでは、集約とは、オブジェクトが、あたかも所有者であるかのように、所有する別のオブジェクトの 1 つまたは複数のインターフェイスをエクスポートすることを意味します。形式的には、これは集約よりも合成またはカプセル化に似ています。ただし、所有オブジェクトのインターフェイスを呼び出してエクスポートされたインターフェイスを実装するのではなく、所有オブジェクト自体のインターフェイスがエクスポートされます。所有オブジェクトは、IUnknownから継承されたインターフェイスのメソッドが実際に所有者の対応するメソッドを呼び出すことを保証する責任があります。これは、所有者の参照カウントが正しく、所有者のすべてのインターフェイスがエクスポートされたインターフェイスを介してアクセス可能である一方、所有オブジェクトの他の (プライベート) インターフェイスにはアクセスできないことを保証するためです。[ 5 ]
複合データ型の複数のインスタンスを格納するために使用される構成は、包含と呼ばれます。このようなコンテナの例としては、配列、連想配列、二分木、リンクリストなどがあります。
UMLでは、包含関係は多重度0..*または1..*で表され、複合オブジェクトが構成クラスの未知の数のインスタンスから構成されていることを示します。
オブジェクトは再帰的に構成することができ、その場合、その型は再帰型と呼ばれます。例としては、さまざまな種類のツリー、DAG(有向非巡回グラフ)、グラフなどがあります。ツリー内の各ノードは、枝または葉のいずれかになります。つまり、各ノードは、別のツリーに属していると同時に、ツリーでもあります。
UMLでは、再帰的合成は、クラス自身との関連、集約、または合成によって表現されます。
複合設計パターンは、複合型に基づいたオブジェクト指向設計であり、再帰的な構成と包含を組み合わせることで、複雑な部分全体階層を実装します。
これはC言語における合成の例です。
enum Employment { SEEKING_JOB , PROFESSIONAL , NON_PROFESSIONAL , RETIRED , STUDENT };struct Person { char name [ 20 ]; int age ; Employment employment ; };この例では、プリミティブ型(非複合型)intとenum Employment複合配列型char[]を組み合わせて複合構造体を形成しますstruct Person。各struct Person構造体は、年齢、名前、雇用形態をそれぞれ「持つ」ことになります。
Cではレコードを構造体または構造と呼びます。Java 、Smalltalk、C++などのオブジェクト指向言語では、レコードをオブジェクト(クラスインスタンス) の中に隠しておくことがよくあります。ML ファミリーの言語では、単にレコードと呼びます。COBOLはレコードを直接サポートした最初の広く普及したプログラミング言語でした。 [ 6 ] ALGOL 68は COBOL から、Pascal は多かれ少なかれ間接的に ALGOL 68 からレコードを取得しました。Common Lisp は構造体とクラス (後者はCommon Lisp オブジェクト システム経由) を提供します。
01 顧客レコード. 03 顧客番号pic 9(8) comp . 03 顧客名. 05 名pic x(15) . 05 イニシャル2 pic x . 05 姓pic x(15) . 03 顧客住所. 05 通り. 07 通り名pic x(15) . 09 番地pic 999 comp . 05 市pic x(10) . 05 国コードpic x(3) . 05 郵便番号pic x(8) . 03 未払い金額pic 9(8) comp .dcl 1 newtypet ベース (P); 2 (a, b, c) 固定ビン(31)、 2 (i, j, k) float、 2 r ptr; 新しい型を割り当てる。
int max = 99; モード newtypet = [0..9] [0..max]struct ( long real a, b, c、short int i, j, k、ref real r ); newtypet newarrayt = (1, 2, 3, 4, 5, 6, heap real := 7)
例えば、連結リストは次のように宣言できます。
モードノード = union (real, int, compl, string) list = struct (node val, ref list next);
ALGOL 68では、等号の左側には型名のみが表示され、最も注目すべき点は、優先順位に関係なく左から右に構造が構築され、読み取ることができる点です。
type a = array [ 1 .. 10 ] of integer ; b = record a , b , c : real ; i , j , k : integer ; end ;#define MAX 99struct Aggregation { double a , b , c ; float r ; short i , j , k ; };struct Aggregation a [ 10 ][ MAX + 1 ];EQUIVALENCEFortran 77には配列はあったものの、正式なレコード/構造体の定義はなかった。通常、複合構造体は次のような文を使って構築されていたCOMMON。
キャラクター名* 32 、住所* 32 、電話番号* 16実際の負債共通/顧客/名前、住所、電話番号、負債type Cust is record Name : Name_Type ; Addr : Addr_Type ; Phone : Phone_Type ; Owing : Integer range 1. . 999999 ; end record ;Ada 95では、タグ付き型(C++のクラスに相当)を通じてオブジェクト指向プログラミングの概念が導入され、Ada 2012では、クラス全体の契約を通じて置換検証のサポートが追加されました。
#define MAX 99;struct Aggregation { double a , b , c ; float & r ; short i , j , k ; };集計a [ 10 ][ MAX + 1 ];max = 99 class NewTypeT : def __init__ ( self ): self . a = self . b = self . c = 0 self . i = self . j = self . k = 0.0 # このクラスのサンプル配列を初期化します。newarrayt = [[ NewTypeT () for i in range ( max + 1 )] for j in range ( 10 )]配列と文字列はFORTRAN 77から継承され、新しい予約語が導入されました。type
type newtypet double precision a , b , c integer * 2 i , j , k * No pointer type REF REAL R end typetype ( newtypet ) t ( 10 , 100 )FORTRAN 90 はFORTRAN IVの概念であるを更新し、組み込みましたNAMELIST。
INTEGER :: jan = 1 、feb = 2 、mar = 3 、apr = 4ネームリスト/週/ 1 月、2 月、3 月、4 月Common Lispは構造体を提供し、ANSI Common Lisp標準ではCLOSクラスが追加されました。
( defclass some-class () (( f :type float ) ( i :type integer ) ( a :type ( array integer ( 10 )))))C/C++ における合成の詳細については、「複合型」を参照してください。
。合成と密接に関連する概念として集約があります。会話では、合成と集約の違いはしばしば無視されます。
{{cite book}}: CS1 メンテナンス: その他 (リンク)