Ugrás a tartalomhoz

Objektum-összetétel

A Wikipédiából, a szabad enciklopédiából

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

[szerkesztés]

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

[szerkesztés]
A bycicle class represented in UML, with three properties: saddle, wheels and parts, the two last having a multiplicity indicating several objects
Objektum-összetétel UML-tulajdonságok használatával objektumok összeállításához

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.

Association between several bicycles each having one owner; Composition of a bicycle with frame parts which make the bicycle; and aggregation of a bicycle with its wheels, which exist without the bicycle
UML jelölés az asszociációhoz, összetételhez és aggregációhoz

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ó

[szerkesztés]

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:

class Professor;  // Máshol definiálva

class Department {
 public:
  Department(const std::string& title): title_(title) {}

 private:
  // Aggregáció: |Professors| tovább létezik, mint a |Department|.
  std::vector<std::weak_ptr<Professor>> members_;
  const std::string title_;
};

class University {
 public:
  University() = default;

 private:
  // Összetétel: |Department|s csak addig létezik, míg a „faculty”-k léteznek
  std::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

[szerkesztés]
Aggregáció COM-ban

A Microsoft komponensobjektum-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]

Speciális formák

[szerkesztés]

Elszigetelés

[szerkesztés]

Az összetett adattípus több példányának tárolására használt összetételt elszigetelésnek nevezzük. Ilyen tárolók például a tömbök, az asszociatív tömbök, a bináris fák és a láncolt listák.

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

[szerkesztés]

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

[szerkesztés]

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.

Kompozíciós típusok C nyelvben

[szerkesztés]

Példa az összetételre C nyelvben:

struct Szemely
{
  int kor;
  char nev[20];
  enum {allas_kereso, szakember, szakmabeli, nyugdijas, tanulo} foglalkoztatas;
};

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

[szerkesztés]

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.

1959 – COBOL
      01  customer-record.
        03  customer-number     pic 9(8) comp.
        03  customer-name.
          05  given-names       pic x(15).
          05  initial-2         pic x.
          05  surname           pic x(15).
        03  customer-address.
          05  street.
            07  street-name     pic x(15).
              09  house-number  pic 999 comp.
          05  city              pic x(10).
          05  country-code      pic x(3).
          05  postcode          pic x(8).
        03  amount-owing        pic 9(8) comp.
1960 – ALGOL 60

ALGOL 60-ban csak a tömbök voltak kompozíciós adattípusok.

1964 – PL/I
dcl 1 newtypet based (P);
 2 (a, b, c) fixed bin(31),
 2 (i, j, k) float,
 2 r ptr;
allocate newtypet;
1968 – ALGOL 68
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.

1970 – Pascal
type
 a = array [1..10] of integer;
 b = record
  a, b, c: real;
  i, j, k: integer;
 end;
1972 – K&R C
#define max 99
struct newtypet {
  double a, b, c;
  float r;
  short i, j, k;
} newarrayt[10] [max + 1];
1977 – FORTRAN 77

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*16
       REAL OWING
       COMMON /CUST/NAME, ADDR, PHONE, OWING
1983 – Ada
type Cust is
 record
  Name  : Name_Type;
  Addr  : Addr_Type;
  Phone : Phone_Type;
  Owing : Integer range 1..999999;
 end record;
1983 – C++
const int max = 99;
class {
  public:
  double a, b, c;
  float &r;
  short i, j, k;
}newtypet[10] [max + 1];
1991 – Python
max = 99
class NewTypeT:
    def __init__(self):
        self.a = self.b = self.c = 0
        self.i = self.j = self.k = 0.0
# Initialise an example array of this class.
newarrayt = [[NewTypeT() for i in range(max + 1)] for j in range(10)]
1992 – FORTRAN 90

A tömbök és a string-ek a FORTRAN 77-ből öröklődtek, de egy új definíció is bevezetésre került: típus.

type newtypet
 double precision a, b, c
 integer*2 i, j, k
* No pointer type REF REAL R
 end type

type (newtypet) t(10, 100)

A FORTRAN 90 frissítette és tartalmazta a FORTRAN IV NAMELIST nevű koncepcióját.

INTEGER :: jan = 1, feb = 2, mar = 3, apr = 4
NAMELIST / week / jan, feb, mar, apr
1994 – ANSI Common Lisp
(defclass some-class ()
  ((f :type float)
   (i :type integer)
   (a :type (array integer (10)))))

Jegyzetek

[szerkesztés]
  1. Gamma, Erich: Design patterns : elements of reusable object-oriented software | WorldCat.org (angol nyelven). www.worldcat.org, 1995. (Hozzáférés: 2023. május 9.)
  2. OMG (2017). "Unified Modelling Language Specification Version 2.5.1". www.omg.org. p. 109-110, 197-201. 2020. október 4.
  3. OMG: Unified Modeling Language Specification Version 2.5.1. www.omg.org, 2017. (Hozzáférés: 2020. október 4.)
  4. Aggregation. Platform SDK for Windows XP SP2. Microsoft. (Hozzáférés: 2007. november 4.)

Fordítás

[szerkeszté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.

Kapcsolódó szócikkek

[szerkesztés]