Komposisjon, aggregering og assosiasjon i Java

1. Introduksjon

Objekter har forhold mellom seg, både i det virkelige liv og i programmering. Noen ganger er det vanskelig å forstå eller implementere disse forholdene.

I denne opplæringen vil vi fokusere på Java's å ta på tre noen ganger lett blandede typer forhold: komposisjon, aggregering og tilknytning.

2. Sammensetning

Sammensetning er en "tilhører" type forhold. Det betyr at ett av objektene er en logisk større struktur, som inneholder det andre objektet. Med andre ord, det er en del eller medlem av det andre objektet.

Alternativt vi kaller det ofte et ”has-a” forhold (i motsetning til et "is-a" forhold, som er arv).

Et rom tilhører for eksempel en bygning, eller med andre ord en bygning har et rom. Så i utgangspunktet er det bare et spørsmål om synspunkt om vi kaller det "tilhører" eller "har-a".

Komposisjon er en sterk type “has-a” -forhold fordi den inneholder objektet. Derfor, gjenstandenes livssyklus er bundet. Det betyr at hvis vi ødelegger eierobjektet, vil medlemmene også bli ødelagt med det. For eksempel er rommet ødelagt med bygningen i vårt forrige eksempel.

Merk at det ikke betyr at objektet som inneholder ikke kan eksistere uten noen av delene. For eksempel kan vi rive ned alle veggene inne i en bygning, og dermed ødelegge rommene. Men bygningen vil fortsatt eksistere.

Når det gjelder kardinalitet, kan et inneholdende objekt ha så mange deler som vi vil. Derimot, alle delene må ha nøyaktig en container.

2.1. UML

I UML indikerer vi komposisjon med følgende symbol:

Legg merke til at diamanten er ved objektet som inneholder og er basen på linjen, ikke et pilspiss. For klarhets skyld tegner vi ofte pilspissen også:

Så da kan vi bruke denne UML-konstruksjonen til eksempelet vårt i bygningsrommet:

2.2. Kildekode

I Java kan vi modellere dette med en ikke-statisk indre klasse:

class Building {class Room {}}

Alternativt kan vi også erklære den klassen i en metodekropp. Det spiller ingen rolle om det er en navngitt klasse, en anonym klasse eller en lambda:

class Building {Room createAnonymousRoom () {return new Room () {@Override void doInRoom () {}}; } Rom createInlineRoom () {class InlineRoom implementerer Room {@Override void doInRoom () {}} returner nytt InlineRoom (); } Rom createLambdaRoom () {return () -> {}; } grensesnittrom {void doInRoom (); }}

Merk at det er viktig at vår indre klasse skal være ikke-statisk, siden den binder alle sine forekomster til den inneholdende klassen.

Vanligvis vil objektet som inneholder tilgang til medlemmene. Derfor bør vi lagre referansene deres:

class Building {Liste rom; klasserom {}}

Merk at alle indre klasseobjekter lagrer en implisitt referanse til deres inneholdende objekt. Som et resultat trenger vi ikke å lagre den manuelt for å få tilgang til den:

class Building {Strengadresse; class Room {String getBuildingAddress () {return Building.this.address; }}}

3. Aggregering

Aggregering er også et "has-a" forhold. Hva skiller det fra komposisjon, at det ikke innebærer å eie. Som et resultat er ikke livssyklusen til gjenstandene bundet: hver og en av dem kan eksistere uavhengig av hverandre.

For eksempel en bil og hjulene. Vi kan ta av hjulene, og de vil fortsatt eksistere. Vi kan montere andre (allerede eksisterende) hjul, eller installere disse på en annen bil, så fungerer alt bra.

Selvfølgelig vil en bil uten hjul eller et løsrevet hjul ikke være like nyttig som en bil med hjulene på. Men det var derfor dette forholdet eksisterte i utgangspunktet: å monter delene til en større konstruksjon, som er i stand til flere ting enn dens deler.

Siden aggregering ikke innebærer å eie, et medlem trenger ikke å være bundet til bare en container. For eksempel er en trekant laget av segmenter. Men trekanter kan dele segmenter som deres sider.

3.1. UML

Aggregering er veldig lik komposisjon. Den eneste logiske forskjellen er aggregering er et svakere forhold.

Derfor er UML-representasjoner også veldig like. Den eneste forskjellen er at diamanten er tom:

For biler og hjul ville vi da gjort:

3.2. Kildekode

I Java kan vi modellere aggregering med en vanlig gammel referanse:

klassehjul {} klasse Bil {Listehjul; }

Medlemmet kan være hvilken som helst type klasse, bortsett fra en ikke-statisk indre klasse.

I kodebiten over har begge klassene sin egen kildefil. Imidlertid kan vi også bruke en statisk indre klasse:

klasse Bil {Listehjul; statisk klassehjul {}}

Merk at Java vil opprette en implisitt referanse bare i ikke-statiske indre klasser. På grunn av dette må vi opprettholde forholdet manuelt der vi trenger det:

klasse Wheel {Car car; } klasse Bil {Listehjul; }

4. Forening

Assosiasjon er det svakeste forholdet mellom de tre. Det er ikke et "has-a" forhold, ingen av gjenstandene er deler eller medlemmer av en annen.

Assosiasjon betyr bare at gjenstandene "kjenner" hverandre. For eksempel en mor og hennes barn.

4.1. UML

I UML kan vi markere en tilknytning med en pil:

Hvis tilknytningen er toveis, kan vi bruke to piler, en pil med en pilspiss i begge ender, eller en linje uten noen pilspisser:

Vi kan representere en mor og hennes barn i UML, og deretter:

4.2. Kildekode

I Java kan vi modellere tilknytning på samme måte som aggregering:

klasse Barn {} klasse Mor {Liste barn; }

Men vent, hvordan kan vi fortelle om en referanse betyr aggregering eller tilknytning?

Vi kan ikke. Forskjellen er bare logisk: om det ene objektet er en del av det andre eller ikke.

Vi må også vedlikeholde referansene manuelt i begge ender, slik vi gjorde med aggregering:

klasse Barn {Mor mor; } klasse Mor {Liste barn; }

5. UML Sidenote

For klarhets skyld ønsker vi noen ganger å definere kardinaliteten til et forhold på et UML-diagram. Vi kan gjøre dette ved å skrive det til endene av pilen:

Merk at det ikke gir mening å skrive null som kardinalitet, fordi det betyr at det ikke er noe forhold. Det eneste unntaket er når vi vil bruke et område for å indikere et valgfritt forhold:

Vær også oppmerksom på at siden det i sammensetningen er nøyaktig en eier, indikerer vi ikke det på diagrammene.

6. Et komplekst eksempel

La oss se et (litt) mer komplekst eksempel!

Vi skal modellere et universitet som har sine avdelinger. Professorer jobber i hver avdeling, som også har venner hverandre.

Vil avdelingene eksistere etter at vi stenger universitetet? Selvfølgelig ikke, derfor er det en komposisjon.

Men professorene vil fortsatt eksistere (forhåpentligvis). Vi må bestemme hva som er mer logisk: om vi betrakter professorer som deler av avdelingene eller ikke. Alternativt: er de medlemmer av avdelingene eller ikke? Ja det er de. Derfor er det en aggregering. På toppen av det kan en professor jobbe i flere avdelinger.

Forholdet mellom professorene er assosiasjon fordi det ikke gir mening å si at en professor er en del av en annen.

Som et resultat kan vi modellere dette eksemplet med følgende UML-diagram:

Og Java-koden ser slik ut:

klasse University {List avdeling; } klasse Avdeling {Listeprofessorer; } klasseprofessor {Listeavdeling; Liste venner; }

Merk at hvis vi stole på begrepene “har-a”, “tilhører”, “medlem-av”, “del-av”, og så videre, kan vi lettere identifisere forholdet mellom objektene våre.

7. Konklusjon

I denne artikkelen så vi egenskapene og representasjonen av sammensetning, aggregering og tilknytning. Vi så også hvordan vi kan modellere disse relasjonene i UML og Java.

Som vanlig er eksemplene tilgjengelige på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found