Zie Scherp Scherper - Hoofdstuk 15
Na dit hoofdstuk kan je:
het verschil tussen compositie en aggregatie uitleggen
de heeft-een-relatie herkennen (tegenover de is-een-relatie)
een object als instantievariabele of via een property in een klasse plaatsen
een heeft-meerdere-relatie modelleren met een array of List
afwegen wanneer je associatie boven overerving kiest
het this-keyword gebruiken
Tip
Eigenlijk niets nieuws: je deed dit waarschijnlijk al, zonder de naam te kennen.
Een object in een ander object gebruiken heet een associatie.
Het verschil zit in de levensduur van het interne object:
Compositie
het interne object kan niet zonder het omliggende
een kamer zonder huis bestaat niet
Aggregatie
beide kunnen op zichzelf bestaan
een motor kan je uit een gesloopte auto redden
Overerving = is een
“een paard is een dier”
Associatie = heeft een
“een mango heeft een pit”, “een vliegtuig heeft een cockpit”
Belangrijk
Een boek is geen pagina. Een boek heeft pagina’s. Dat is dus associatie, geen overerving. (“Heeft meerdere” wijst op een array of List.)
De twee relaties sluiten elkaar niet uit:
Sportwagen
is een
overerving
Auto
heeft een
compositie
Motor
Dus een Sportwagen heeft via overerving ook een Motor.
Tip
Overerving en compositie werken samen: de child erft de associaties van zijn parent.
Compositie: volle ruit aan de kant van het omliggende object.
Aggregatie: lege ruit. Een getal duidt de verhouding aan.
Een PC heeft een HardeSchijf, dus zit er in PC een instantievariabele van het type HardeSchijf:
Vergeet niet die HardeSchijf ook te instantiëren, anders blijft hij de hele levensduur null.
Meteen bij de instantievariabele, of via de constructor:
Sterft de PC, dan sterft de interne schijf mee: dat is compositie.
Maak het object buiten de PC aan en plug het in via een property:
Er blijft een externe referentie (schijf), dus de GC ruimt hem niet op met de PC: dat is aggregatie.
Het interne object staat apart in de heap; de PC bewaart enkel een referentie ernaar.
Compositie geeft dus geen groot monolithisch object: alles blijft netjes verbonden via referenties.
Waarschuwing
Een intern object aanspreken dat nooit werd aangemaakt, geeft een NullReferenceException. Controleer dus op null.
Een boek heeft veel pagina’s, dus een array of List. Hou de collectie privé en bied een eigen methode aan:
Belangrijk
Een interne List rechtstreeks via een publieke set aanbieden is riskant: iemand kan dan zomaar Clear() aanroepen. Hou het een blackbox.
Favor composition over inheritance.
In de praktijk gebruik je veel vaker een heeft-een dan een is-een-relatie.
Belangrijk
patient.Hart = donor.Hart; kopieert niet: beide verwijzen nu naar hetzelfde Hart-object. Een object delen is geen object kopiëren. Wees dus geen Dokter Frankenstein van C#: te veel compositie maakt een klasse minder herbruikbaar.
In een spel heeft een Held twee handen, elk met 0 of 1 Wapen dat schade doet:
Tip
Een lege hand is gewoon null. Reik je het wapen door aan een andere held, dan is het aggregatie: het wapen leeft los van de held.
this is de referentie naar het huidige object.
een object kan zichzelf meegeven als parameter
een instantievariabele of property aanroepen die een gelijke naam heeft als een lokale variabele
een andere constructor aanroepen (: this(...), hoofdstuk 11)
Belangrijk
this werkt enkel in een instance-context (gewone methoden, properties, constructors). In een static methode bestaat er geen “huidig object”.
this.Levens haalt de property, ook al heet de parameter net zo.
Tip
Beter nog: geef je parameter gewoon een andere naam, dan heb je this hier niet eens nodig.
Het object geeft zichzelf (this) door aan een externe methode, zodat een werknemer zelf kan checken of die promoveerbaar is.
Een associatie is een object-in-een-object; compositie (sterft mee) of aggregatie (los leefbaar)
De heeft-een-relatie wijst op associatie, de is-een-relatie op overerving
Plaats het interne object via een instantievariabele, constructor of property
“Heeft meerdere” doe je met een array of List, liefst achter een nette blackbox
this verwijst naar het huidige object; favor composition over inheritance
Tip
Volgende halte: polymorfisme, waar één naam vele vormen aanneemt.
Kennisclips
Hoe doen andere programmeertalen hetzelfde? En een korte zoek-de-fout, om zo kritisch mogelijk naar code te leren kijken.
In Python werkt de “heeft een”-relatie quasi identiek: gewoon een object als instantievariabele.
“Een object in een ander object” is geen C#-eigenaardigheid, maar geldt in elke OO-taal. Net als favor composition over inheritance.
In Python bestaat er geen impliciet this: je geeft het huidige object expliciet mee als eerste parameter, traditioneel self.
C#
regelt this verborgen via de compiler
Python
toont datzelfde object gewoon als eerste parameter
JavaScript
heeft wél this, maar met beruchte binding-regels: waarnaar het verwijst hangt af van hoe je een functie aanroept
Onderstaande C#-code wil een PC met een harde schijf opbouwen via aggregatie en daarna de capaciteit tonen. Toch crasht het programma. Wat loopt er mis?
Opmerking
CHardeSchijf werd nooit een object toegewezen en is dus null. Bij CHardeSchijf.MaxCapacity krijg je daarom een NullReferenceException. Steek eerst een harde schijf in de PC (mijnPC.CHardeSchijf = new HardeSchijf();) of controleer op null in ToString voor je de property gebruikt.
Een handige samenvattende poster (Opgelet: gemaakt m.b.v. ChatGPT Image Gen 2).