A számítástudományban az objektum-összetétel és az objektumegyesítés szorosan egymáshoz köthető műveletek arra irányulóan, hogy objektumokat vagy adattípusokat komplexebb formává alakítsunk át. A gyakorlatban az összetétel és az egyesítés közti különbségeket gyakran elhanyagolják, nem veszik figyelembe. Az összetétel gyakori példái olyan objektumok, amik objektumorientált programozásban, változókban, sorozatokban, vagy különféle gráf struktúrákban vannak felhasználva. Az objektum-összetétel továbbá szoros összefüggésben áll az adat struktúrákkal is, de nem azonos azokkal.
Az objektum-összetétel az információ logikai, fogalmi felépítésére utal, nem pedig az adatstruktúrák fizikai implementálására. Például, a sorozatok különböznek a „set” adattípustól, mivel többek között az összeállított elemek sorrendje egy fontos feltétel az előbbinek, de az utóbbinak nem. Olyan adatstruktúrák, mint például a sor, a láncolt lista, a hash tábla, használhatók arra, hogy valamelyiküket implementáljuk. Talán zavaró, de előfordul, hogy ugyanazt a fogalmat használják mind az adatstruktúrákra, mind az összetételre. Például, a bináris fa mindkettőre utalhat: adatstruktúraként az elemek lineáris sorozatban való hozzáférését jelenti, ahol az elemek tényleges pozíciója lényegtelen, mivel a fa átrendezhető anélkül, hogy elveszítse funkcióját. Ennek ellenére, mint objektum-összetétel, a bináris fában az elemek pozíciója releváns, hiszen megváltoztatva azokat, a fa funkciója is elvész (ez történik például a kladogramokban is).
Programozási technikák
Az objektumorientált programozás az objektumok egységbezárásán alapul, két fő technikát használ erre: az altípusokat és az objektum-összetételt.[1] Objektum-összetétel esetén már meglévő, összetett objektumon belül kombinálunk kisebb objektumokat egy komplexebbé, illetve, ezzel egy időben biztosítjuk minden elem egységbezárását egy jól definiált interface segítségével anélkül, hogy az objektumok belseje láthatóvá válna. Ebből is látható, hogy az objektum-összetétel mennyire különbözik az adatstruktúráktól, mivel azoknál nem szükséges az egységbezárás használata.
Osztály-alapú és típusos programozási nyelvekben a típusok elkülöníthetők összetett és nem összetett típusokra, az összetétel pedig tekinthető a típusok közti kapcsolatnak is: az összetett típus egy objektumának (pl. „autó”) van objektuma egy másik típusból (pl. „kerék”). Mikor egy összetett objektum több al-objektumot is tartalmaz azonos típusból, olyankor szerepekhez is hozzárendelhetők. Például, a „Point” objektum három számot tartalmazhat, mindegyik szám az adott pont különböző tengelyektől (x, y, z) mért távolságát reprezentálja.
Az összetételt muszáj elkülöníteni az altípusosságtól, mivel az utóbbi egy már létező, általános típusokhoz ad részleteket, így egy specifikusabb adat típust hoz létre. Például, az „autó” egy specifikusabb típusa a járműnek: „Az autó jármű.” (Is-a kapcsolat). Az altípusosság nem mondja ki a kapcsolatot két különböző objektum közt, hanem azt mondja, hogy egy bizonyos típus objektumai egyidejűleg objektumai egy másik típusnak is.
A prototípus-alapú programozási nyelvekben, mint amilyen a JavaScript is, az objektumok dinamikusan öröklik a tulajdonságaikat egy prototípus objektumtól, már a példányosításuk pillanatában. Az összetétel megkülönböztetendő a prototípusoktól: az újonnan példányosított objektum örökli a prototípusának összetételét, de akár saját magát is kompozicionálhatja.
UML modellezési technika
UML modellezésben az objektumok létrehozhatók koncepcionálisan, anélkül, hogy programozási nyelv segítségével lennének implementálva. Négyféle lehetőség van arra, hogy UML-ben objektumokat állítsunk össze: property, egyesítés, aggregáció és összetétel[2]:
A property az osztályának egy attribútumát reprezentálja.
Az egyesítés az egyesített osztályok közti szemantikai kapcsolatot reprezentálja.Az egyesület tagvége a társított osztály egy tulajdonságának felel meg.
Az aggregáció egyfajta egyesítés, ami a rész/egész kapcsolatot modellezi az egész és a hozzá köthető komponensek közt.
Az összetétel az aggregáció egy fajtája, ami a rész/egész kapcsolatot modellezi az egész és a kizárólagosan tulajdonlott részek közt.
Az aggregált egész és annak komponensei közt egy gyenge „has-a” kapcsolat van: a komponensek több egésznek is részei lehetnek, és ahhoz, hogy más objektumokon keresztül is elérhetők legyenek, túl kell élniük az aggregált egészüket.[3]
Az összetétel és annak részei közt erős „has-a” kapcsolat van: az összesített objektumnak egyedülálló felelőssége van arra vonatkozóan, hogy életben tartsa és tárolja a kompozicionált objektumokat. A kompozicionált objektum része legfeljebb egy összetételnek, ezért UML-ben az összetételnek szűkebb értelme van, mint egy általános objektum-összetételnek.
A grafikus jelölés a következőket ábrázolja:
a propertyt mint egy típusos elemet a körbezárt osztályon belül
az asszociációt, mint sima vonalat a társított osztályok között,
az aggregációt, mint egy kitöltetlen gyémánt forma az aggregált oldalon, másik oldalon sima vonal
az összetétel kitöltött gyémántként a kompozit oldalán és egy folytonos vonal.
Aggregáció
Az aggregáció abban különbözik az átlagos objektum-összetételtől, hogy nem jár tulajdonlással: összetétel esetén, ha a tulajdonlott objektum megsemmisül, akkor a benne lévő objektumok is megsemmisülnek. Aggregáció esetén ez nem feltétlenül igaz. Például: egy egyetemnek van több tanszéke (pl. kémiai tanszék stb.) és minden tanszéken több professzor is tanít. Ha az egyetem bezár, megszűnnek a tanszékei, de a professzorok továbbra is megmaradnak, így mondhatjuk, hogy az egyetem a tanszékek összetétele, a tanszékek viszont a professzorok aggregációja. Illetve, a gyakorlatban is láthatjuk, hogy egy professzor dolgozhat több tanszéken is, de az adott tanszék csakis egy egyetem tulajdona lehet.
Az összetételt általában úgy valósítják meg, hogy egy objektum egy másik objektumot is tartalmazzon. Például így néz ki C++ nyelven:
classProfessor;// Máshol definiálvaclassDepartment{public:Department(conststd::string&title):title_(title){}private:// Aggregáció: |Professors| tovább létezik, mint a |Department|.std::vector<std::weak_ptr<Professor>>members_;conststd::stringtitle_;};classUniversity{public:University()=default;private:// Összetétel: |Department|s csak addig létezik, míg a „faculty”-k léteznekstd::vector<Department>faculty_={Department("chemistry"),Department("physics"),Department("arts"),};};
Az aggregáció során az objektum csak hivatkozást vagy mutatót tartalmazhat az objektumra (és nem vállal felelősséget érte).
Néha az aggregációt összetételnek nevezik, amikor a közönséges összetétel és az aggregáció közötti különbségek nem fontosak.
A fenti kód így nézne ki UML osztálydiagramként:
Aggregáció COM-ban
A Microsoftkomponensobjektum-modelljében (Component Object Model) az aggregáció azt jelenti, hogy egy objektum (mintha a tulajdonosa lenne), egy másik, tulajdonában lévő objektum, egy, vagy több interfészét exportálja. Formálisan ez jobban hasonlít az összetételhez vagy az egységbezáráshoz, mint az aggregációhoz. Ahelyett azonban, hogy az exportált interfészek a tulajdonlott objektum interfészeinek meghívásával lennének implementálva, maguk a tulajdonlott objektum interfészei kerülnek exportálásra. A tulajdonlott objektum felelős annak biztosításáért, hogy az IUnknown-tól örökölt interfészek metódusai valóban meghívják a tulajdonos megfelelő metódusait. Ez garantálja, hogy a tulajdonos referenciaszáma helyes, és a tulajdonos összes felülete elérhető legyen az exportált felületen keresztül, miközben a tulajdonlott objektum egyéb (privát) felületei nem érhetők el.[4]
Az UML-ben az elszigetelés 0..* vagy 1..* többszörösével van ábrázolva, jelezve, hogy az összetett objektum az összeállított osztály ismeretlen számú példányából áll.
Rekurzív összetétel
Az objektumok rekurzív módon is összeállíthatók, és típusukat ezután rekurzív típusnak nevezzük. A példák közé tartoznak a különféle fák, DAG-ok és grafikonok. A fa minden csomópontja lehet ág vagy levél; más szóval, minden csomópont egyben fa is, amikor egy másik fához tartozik.
Az UML-ben a rekurzív összetételt egy osztály önmagával való asszociációjával, aggregációjával vagy összetételével ábrázolják.
Összetett minta
Az összetett tervezési minta egy összetett típusokon alapuló objektumorientált tervezés, amely a rekurzív összetételt és az elszigetelést ötvözi, hogy összetett rész-egész hierarchiákat valósítson meg.
Ebben a példában a primitív (nem összetett) int, enum { allas_kereso, szakember, szakmabeli, nyugdijas, tanulo } és a char[] összetett tömbtípus kombinációja alkotja a Szemely összetett szerkezetet. Minden Szemely struktúrának „van” egy életkora, neve és foglalkoztatási típusa.
Azösszetétel fejlődése más programozási nyelvekben
C nyelvben egy rekordot struktúrának nevezünk; az objektumorientált nyelvekben (pl. Java, Smalltalk és C++) gyakran rejtve tartjuk a rekordjainkat az objektumok (osztálypéldányok) belsejében; az ML család nyelvei viszont egyszerűen csak rekordoknak nevezik őket. A COBOL volt az első széles körben elterjedt programozási nyelv, amely közvetlenül támogatta a rekordokat.
int max = 99;
mode 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)
A láncolt lista deklarálható így is:
mode node = union (real, int, compl, string),
list = struct (node val, ref list next);
Az ALGOL 68 esetében csak a típusnév jelenik meg az egyenlőség bal oldalán, és a konstrukció balról jobbra készül – és olvasható – a prioritások figyelembevétele nélkül.
Fortran 77-ben ugyan vannak tömbök, de hiányoztak a formális rekord/struktúra definíciók. Az összetett szerkezetek jellemzően EQUIVALENCE vagy COMMON utasítások használatával készültek:
CHARACTER NAME*32,ADDR*32,PHONE*16REAL OWINGCOMMON/CUST/NAME,ADDR,PHONE,OWING
max=99classNewTypeT:def__init__(self):self.a=self.b=self.c=0self.i=self.j=self.k=0.0# Initialise an example array of this class.newarrayt=[[NewTypeT()foriinrange(max+1)]forjinrange(10)]
↑Aggregation. Platform SDK for Windows XP SP2. Microsoft. (Hozzáférés: 2007. november 4.)
Fordítás
Ez a szócikk részben vagy egészben az Object composition című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.