← Python/Eigen typen
Les 7 van 8
MODULE 07 · 07◷ 28 min

Objecten samenstellen en bewust delen

Na deze les kun je
  • Een relatie tussen echte objecten modelleren.
  • Een gedeeld onderdeel bewust via de bestaande verwijzing wijzigen.
  • Een zelfstandige kopie met eigen binnenste objecten maken.

Een boek heeft een auteur, en meerdere boeken kunnen dezelfde auteur hebben. Je kunt die relatie in je gegevensmodel zichtbaar maken. Daarbij moet je bewust kiezen of de boeken één auteur delen of ieder een zelfstandig auteursobject bewaren.

Een object bevat een ander object

Compositie betekent dat een object andere objecten gebruikt als onderdelen. Een Book kan bijvoorbeeld een Author in het attribuut author bewaren. Met book.author.name volg je eerst de relatie naar de auteur en lees je daarna diens naam.

Beide delen zijn gewone objecten met hun eigen toestand. Het buitenste object kan die toestand gebruiken, maar maakt het binnenste object niet vanzelf opnieuw. Je eerdere kennis van verwijzingen blijft dus van toepassing.

De relatie leidt naar het binnenste object
class Author:
    def __init__(self, name):
        self.name = name

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

writer = Author("Ada")
book = Book("De reis", writer)
print(book.title)
print(book.author.name)
Verwachte uitvoer
De reis
Ada

Je hoeft de auteursnaam daardoor niet op iedere plek als los veld te herhalen. Het model laat zien welk gegeven bij het boek hoort en welk gegeven bij de auteur. Een extra methode kan via die relatie een leesbare beschrijving maken.

Delen kan de bedoeling zijn

Wanneer twee boeken hetzelfde Author-object ontvangen, bewaren zij volgens dit voorbeeld dezelfde verwijzing. Een wijziging aan de auteur is dan via beide boeken te zien. Dat is passend als zij werkelijk één gedeelde auteur voorstellen.

Twee boeken delen dezelfde auteur
class Author:
    def __init__(self, name):
        self.name = name

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

writer = Author("Ada")
first = Book("De reis", writer)
second = Book("Het vervolg", writer)
writer.name = "Ana"
print(first.author.name)
print(second.author.name)
print(first is second)
print(first.author is second.author)
Verwachte uitvoer
Ana
Ana
False
True
VerwijzingObject waarnaar zij verwijst
first.authorDe gedeelde auteur
second.authorDezelfde gedeelde auteur

Een nieuwe Book is hier wel een nieuw buitenste object. Dat feit zegt nog niets over de identiteit van zijn onderdelen. Je moet bij een kopie dus ook onderzoeken wat er met die binnenste verwijzingen gebeurt.

Of een zelfstandige kopie maken

Soms vraagt het contract juist dat een wijziging aan een kopie het origineel niet raakt. Dan maak je zowel een nieuw buitenste object als de benodigde nieuwe onderdelen. Bij een eenvoudig adresmodel kun je de bestaande adresvelden lezen en daarmee een nieuw Address maken.

Je hoeft daarvoor niet ieder object in het hele programma blind te kopiëren. Bepaal welke delen van dit model eigen toestand moeten krijgen. Onveranderlijke tekstwaarden kunnen worden overgenomen zonder een nieuwe veranderlijke gegevensstructuur te delen.

Veelgemaakte fout: alleen de buitenkant kopiëren

Person(original.name, original.address) kan een nieuwe persoon maken die nog hetzelfde adres bevat. Wanneer je daarna via de kopie de stad wijzigt, verandert het gedeelde adres ook voor de oorspronkelijke persoon. De buitenste identiteiten zijn verschillend, maar de innerlijke identiteit is nog dezelfde.

Een waardevergelijking van de beginvelden vindt deze fout niet. Beide adressen bevatten aanvankelijk dezelfde stad en straat. Daarom controleren de opdrachten ook de echte objectverwijzingen en het gedrag na een wijziging.

Jouw adresafspraken

In deze oefening ontvangt Person bewust een bestaand Address en bewaart precies die verwijzing. Het lezen van de stad volgt de relatie naar dat adres. Een verhuisbewerking verandert de stad op het bestaande adres; de naam en straat blijven behouden.

Twee personen die bewust dat adres delen, zien dus dezelfde verhuizing. Dat is de gekozen afspraak voor deze handeling. Het is geen automatische regel dat ieder gegevensmodel zijn adres altijd moet kopiëren.

copy_person heeft juist een ander contract: zij maakt een nieuwe persoon met een nieuw adres en dezelfde beginvelden. Een verhuizing van die kopie mag het originele adres niet veranderen. Bewaar tekst exact en voeg geen eigen normalisatie- of validatieregels toe.

AAN DE SLAG 0/4
1

De ontvangen relatie bewaren

Vul Person.__init__(name, address) in: bewaar name precies en bewaar hetzelfde ontvangen Address-object op address. Kopieer dit adres hier bewust niet. De Address-klasse in de starter is al compleet.

2

Door de relatie heen lezen

Maak city_of(person) die de city van het adres van deze persoon precies teruggeeft. Verander de naam, straat of stad niet en voeg geen opschoonregel toe.

3

Het gedeelde onderdeel wijzigen

Maak move(person, city) die de city op het bestaande adres van person verandert en None teruggeeft. Behoud naam, straat en adresidentiteit. Twee personen die dit adres delen moeten dezelfde verhuizing zien.

4

Beide niveaus zelfstandig kopiëren

Maak copy_person(person) die een nieuwe Person met een nieuw Address en precies dezelfde naam, straat en stad teruggeeft. Een wijziging aan het adres van de kopie mag het oorspronkelijke adres niet raken.

Onthoud dit

  • Compositie modelleert relaties tussen echte objecten.
  • Een nieuw buitenste object kan nog steeds innerlijke objecten delen.
  • Leg vast of delen of kopiëren de bedoeling is en toets ook latere wijzigingen.

Hierna combineer je eigen toestand, objectgedrag en foutpaden in een reserveringsmodel.

main.py
UitvoerPython
›
›_

Hier komt je resultaat.

Voer je code uit en ontdek
wat je hebt gemaakt.

0/4 stappen
EVEN MEEKIJKEN

Bekijk hoe het kan.

Je mag de oplossing bekijken. Deze poging telt dan niet mee als afgeronde les. Met Reset kun je daarna opnieuw zelf oefenen.