Összetétel, összesítés és társítás Java-ban

1. Bemutatkozás

Az objektumok között vannak kapcsolatok, mind a való életben, mind a programozás során. Néha nehéz megérteni vagy megvalósítani ezeket a kapcsolatokat.

Ebben az oktatóanyagban arra összpontosítunk, hogy a Java felvesz három, néha könnyen összekeverhető kapcsolattípust: összetétel, összesítés és társítás.

2. Összetétel

Fogalmazás „hozzátartozó” típusú kapcsolat. Ez azt jelenti, hogy az egyik objektum logikailag nagyobb szerkezet, amely tartalmazza a másik objektumot. Más szavakkal, a másik objektum része vagy tagja.

Alternatív megoldásként gyakran „van-van” kapcsolatunknak hívjuk (szemben az „is-a” kapcsolattal, amely az öröklés).

Például egy helyiség egy épülethez tartozik, más szóval az épületnek van szobája. Tehát alapvetően az, hogy „hozzátartozónak” vagy „van-nak” hívjuk, csak nézőpont kérdése.

A kompozíció erős fajta „van-van” kapcsolat, mert a tartalmat tartalmazó tárgy birtokolja. Ebből kifolyólag, a tárgyak életciklusa meg van kötve. Ez azt jelenti, hogy ha elpusztítjuk a tulajdonos tárgyat, annak tagjai is megsemmisülnek vele. Például a helyiség az előző példánkban szereplő épülettel tönkremegy.

Vegye figyelembe, hogy ez nem jelenti azt, hogy a tartalmú objektum nem létezhet egyetlen része nélkül. Például egy épület belsejében le tudjuk bontani az összes falat, így tönkretehetjük a helyiségeket. De az épület továbbra is létezni fog.

Kardinalitás szempontjából egy tartalmú objektumnak annyi része lehet, amennyit csak akarunk. Azonban, az összes alkatrésznek pontosan egy tartálynak kell lennie.

2.1. UML

Az UML-ben a kompozíciót a következő szimbólummal jelezzük:

Ne feledje, hogy a gyémánt a tároló tárgynál van, és a vonal alapja, nem pedig nyílhegy. Az egyértelműség kedvéért gyakran felhívjuk a nyílhegyet is:

Tehát akkor ezt az UML konstrukciót használhatjuk az Épület-szoba példánkhoz:

2.2. Forráskód

A Java-ban ezt nem statikus belső osztállyal modellezhetjük:

osztály épület {osztály szoba {}}

Alternatív megoldásként deklarálhatjuk azt az osztályt a módszer törzsében is. Nem számít, hogy ez egy megnevezett osztály, egy névtelen osztály vagy egy lambda:

osztályépület {Room createAnonymousRoom () {return new Room () {@Override void doInRoom () {}}; } Room createInlineRoom () {class InlineRoom megvalósítja a Room {@Override void doInRoom () {}} return new InlineRoom (); } Room createLambdaRoom () {return () -> {}; } interfész szoba {void doInRoom (); }}

Ne feledje, hogy elengedhetetlen, hogy belső osztályunk ne statikus legyen, mivel az összes példányát a benne lévő osztályhoz köti.

Általában a tároló objektum hozzáférni akar a tagjaihoz. Ezért tároljuk referenciáikat:

osztály Épület {Szobák felsorolása; osztályterem {}}

Ne feledje, hogy az összes belső osztályú objektum implicit hivatkozást tárol az őket tartalmazó objektumra. Ennek eredményeként a hozzáféréshez nem kell manuálisan tárolnunk:

osztály Épület {String address; osztályterem {String getBuildingAddress () {return Building.this.ddress; }}}

3. Összesítés

Az összesítés szintén „van” kapcsolat. Mi különbözteti meg a kompozíciótól, hogy nem jár a birtoklással. Ennek eredményeként az objektumok életciklusa nincs összekötve: mindegyikük egymástól függetlenül létezhet.

Például egy autó és annak kerekei. Levehetjük a kerekeket, és még mindig léteznek. Felszerelhetünk más (már létező) kerekeket, vagy felszerelhetjük ezeket egy másik autóra, és minden rendben működik.

Természetesen egy kerek nélküli autó vagy egy leválasztott kerék nem lesz olyan hasznos, mint egy autó, amelynek kerekei vannak. De ezért létezett elsősorban ez a kapcsolat: a szerelje össze az alkatrészeket egy nagyobb konstrukcióra, amely több dologra képes, mint a részei.

Mivel az összesítés nem jár tulajdonlással, egy tagot nem kell csak egy tartályhoz kötni. Például egy háromszög szegmensekből áll. De a háromszögek megoszthatják a szegmenseket oldalukként.

3.1. UML

Az összesítés nagyon hasonlít az összetételhez. Az egyetlen logikai különbség az összesítés egy gyengébb kapcsolat.

Ezért az UML ábrázolások is nagyon hasonlóak. Az egyetlen különbség az, hogy a gyémánt üres:

Autók és kerekek esetében tehát tennénk:

3.2. Forráskód

A Java-ban egyszerű összesítéssel modellezhetjük az összesítést:

osztály Kerék {} osztály Autó {Kerekek felsorolása; }

A tag bármilyen típusú osztály lehet, a nem statikus belső osztály kivételével.

A fenti kódrészletben mindkét osztálynak külön forrásfájlja van. Használhatunk azonban statikus belső osztályt is:

osztály Autó {Kerekek felsorolása; statikus osztályú kerék {}}

Ne feledje, hogy a Java csak nem statikus belső osztályokban hoz létre implicit hivatkozást. Emiatt kézzel kell fenntartanunk a kapcsolatot, ahol szükségünk van rá:

osztály Kerék {Autó autó; } osztályú Autó {Kerekek felsorolása; }

4. Egyesület

Az asszociáció a leggyengébb kapcsolat a három között. Ez nem "van" kapcsolat, egyik objektum sem része vagy tagja egy másiknak.

Az asszociáció csak azt jelenti, hogy az objektumok „ismerik” egymást. Például egy anya és gyermeke.

4.1. UML

Az UML-ben egy asszociációt nyíllal jelölhetünk meg:

Ha az asszociáció kétirányú, használhatunk két nyíl, egy nyíl, amelynek mindkét végén nyílhegy van, vagy egy nyíl nélküli nyíl:

Képviselhetünk egy anyát és gyermekét az UML-ben, majd:

4.2. Forráskód

A Java-ban az asszociációt ugyanúgy modellezhetjük, mint az összesítést:

osztály Gyermek {} osztály Anya {Gyermekek felsorolása; }

De várj, honnan lehet megállapítani, hogy a hivatkozás összesítést vagy asszociációt jelent-e?

Nos, nem tehetjük. A különbség csak logikus: az egyik objektum része-e a másiknak vagy sem.

Ezenkívül mindkét oldalon manuálisan kell karbantartanunk a referenciákat, mint az összesítésnél:

osztály Gyermek {Anya anya; } osztály Anya {Sorolja fel a gyermekeket; }

5. UML Sidenote

Az egyértelműség kedvéért néha meg akarjuk határozni egy kapcsolat számosságát egy UML-diagramon. Megtehetjük, ha a nyíl végére írjuk:

Ne feledje, hogy nincs értelme nullát írni kardinalitásnak, mert ez azt jelenti, hogy nincs kapcsolat. Az egyetlen kivétel az, amikor egy tartományt akarunk használni egy opcionális kapcsolat jelölésére:

Vegye figyelembe azt is, hogy mivel összetételben pontosan egy tulajdonos van, ezért nem tüntettük fel az ábrákon.

6. Komplex példa

Lássunk egy (kicsit) összetettebb példát!

Modellezünk egy egyetemet, amelynek tanszékei vannak. Minden tanszéken professzorok dolgoznak, akiknek vannak barátai is.

Léteznek-e a tanszékek az egyetem bezárása után? Természetesen nem, ezért kompozíció.

De a professzorok továbbra is léteznek (remélhetőleg). El kell döntenünk, hogy melyik logikusabb: ha a professzorokat a tanszék részének tekintjük, vagy sem. Alternatív megoldásként: tagjai-e az osztályoknak vagy sem? Igen. Ezért ez egy összesítés. Ráadásul egy professzor több tanszéken is dolgozhat.

A professzorok közötti kapcsolat asszociáció, mert nincs értelme azt mondani, hogy a professzor egy másik része.

Ennek eredményeként modellezhetjük ezt a példát a következő UML-diagrammal:

És a Java kód így néz ki:

osztály Egyetem {Lista tanszék; } osztály Tanszék {Professzorok listája; } osztály professzor {List osztály; Sorold fel a barátaidat; }

Ne feledje, hogy ha mi támaszkodjon a „van-e”, „tartozik-e”, „tagja”, „része” kifejezésekre, és így tovább, könnyebben azonosíthatjuk az objektumaink közötti kapcsolatokat.

7. Következtetés

Ebben a cikkben az összetétel, az összesítés és az asszociáció tulajdonságait és ábrázolását láttuk. Azt is láttuk, hogyan modellezhetjük ezeket a kapcsolatokat UML-ben és Java-ban.

Szokás szerint a példák elérhetők a GitHub oldalon.