Een samenhangend object met eigen begintoestand maken.
Geldige en afgewezen handelingen met toestandbehoud uitvoeren.
Afgeleide waarden en zelfstandige momentopnamen aanbieden.
Een reservering heeft een capaciteit en een eigen lijst deelnemers. Namen toevoegen en verwijderen lijkt eenvoudig, maar fouten mogen de bestaande reservering niet beschadigen. Je combineert nu initialisatie, methoden, een afgeleide property en bewuste kopieën in één samenhangend model.
De afspraken bij elkaar houden
Een bruikbaar object bewaart zijn gegevens en biedt handelingen die de afgesproken toestand behouden. Voor Reservation moet het aantal deelnemers tussen nul en de capaciteit blijven. Iedere reservering begint met een eigen lege deelnemerslijst.
Een capaciteit van nul is geldig: er is dan direct geen plaats beschikbaar. Een negatieve capaciteit wordt geweigerd. Deze grens wordt bij het maken van de instantie gecontroleerd, zodat een later gebruikte reservering meteen een passende begintoestand heeft.
Eerst een ander model bekijken
Het voorbeeld gebruikt een materiaalbak met een maximumaantal labels. De handeling controleert haar grens voordat zij een label toevoegt. Voorspel welke inhoud overblijft nadat een toevoeging is geweigerd.
Een grens controleren voordat de inhoud verandert
class BinError(ValueError):
pass
class MaterialBin:
def __init__(self, limit):
self.limit = limit
self.labels = []
def put(self, label):
if len(self.labels) >= self.limit:
raise BinError("bak is vol")
self.labels.append(label)
bin = MaterialBin(1)
bin.put("Bouten")
try:
bin.put("Moeren")
except BinError as error:
print(error)
print(bin.labels)
Verwachte uitvoer
bak is vol
['Bouten']
De handler kan de reden tonen, terwijl het object zijn bestaande inhoud behoudt. Dat is dezelfde samenwerking tussen invariant en foutafhandeling die je eerder bij een property zag. Een passende fouttekst bewijst pas iets wanneer de toestand na de fout ook klopt.
Een eigen categorie voor afwijzingen
Gebruik in de opdrachten BookingError als subklasse van ValueError. Zo kan een aanroeper de afgesproken reserveringsproblemen gericht afhandelen. Een normale programmeerfout wordt daardoor niet automatisch een gewone afwijzing.
De namen worden met strip opgeschoond. Een daarna lege naam wordt geweigerd, terwijl hoofdletters en de overige tekst behouden blijven. De naamcontrole vindt plaats voordat je de bestaande deelnemerslijst wijzigt.
Situatie bij toevoegen
Afspraak
Lege opgeschoonde naam
Afwijzen zonder wijziging
Naam bestaat al
Die dubbele naam afwijzen
Geen plaats meer
De volle reservering melden
Overige geldige naam
Achteraan toevoegen
Een dubbele naam krijgt dus haar eigen reden, ook wanneer de reservering tegelijk vol is. Die volgorde maakt de reactie voorspelbaar. Kies niet op iedere plek een andere willekeurige controlevolgorde.
Een afgeleide waarde lezen
De property remaining geeft de capaciteit min het actuele aantal deelnemers. De aanroeper hoeft deze telling niet zelf bij te houden. Na een geslaagde toevoeging of verwijdering hoort de gelezen waarde meteen te kloppen.
Een annuleringsmethode geeft een echte boolean terug. Een aanwezige naam verwijderen levert True; een onbekende naam levert False en verandert de reservering niet. Gebruik voor het zoeken dezelfde opgeschoonde naamvorm als bij toevoegen.
Veelgemaakte fout: interne toestand weggeven
Een methode die de interne deelnemerslijst rechtstreeks teruggeeft, geeft de aanroeper ook een wijzigingsroute buiten jouw controles. Die kan dan extra namen toevoegen zonder de capaciteit of duplicaten te laten controleren. Geef voor een momentopname daarom een nieuwe lijst met dezelfde huidige namen terug.
Een zelfstandige lijst geeft geen interne wijzigingsroute
class MaterialBin:
def __init__(self):
self.labels = ["Bouten"]
def snapshot(self):
return list(self.labels)
bin = MaterialBin()
view = bin.snapshot()
view.append("Alleen in de kopie")
print(view)
print(bin.labels)
print(view is bin.labels)
Verwachte uitvoer
['Bouten', 'Alleen in de kopie']
['Bouten']
False
Die momentopname beschrijft de toestand op het moment van opvragen. Een latere wijziging aan de ontvangen lijst raakt de reservering niet. Een volgende momentopname bevat wel de actuele gegevens en is opnieuw een zelfstandig lijstobject.
Jouw model afronden
Bewaar de oorspronkelijke volgorde van de deelnemers die overblijven. Een afgewezen toevoeging mag geen naam verwijderen, en een mislukte annulering mag geen plek creëren. Ook twee aparte reserveringen houden ieder hun eigen lijst, zelfs wanneer eigenaar en capaciteit gelijk zijn.
De controles onderzoeken echte instanties, actuele properties, retourwaarden en toestand na een geworpen fout. Je hoeft geen programma te printen dat een reservering beschrijft. Je maakt het object waarmee zulke handelingen werkelijk kunnen worden uitgevoerd.
AAN DE SLAG 0/4
1
Een geldige eigen begintoestand
Maak Reservation(owner, capacity) die owner precies bewaart en een niet-negatieve capacity accepteert. Een negatieve capaciteit werpt BookingError met capaciteit moet nul of hoger zijn. Iedere instantie krijgt een nieuwe lege _participants-lijst; BookingError blijft een subklasse van ValueError.
2
Gecontroleerd toevoegen
Maak add(name): strip de naam, weiger een lege naam met BookingError en naam ontbreekt, daarna een dubbele naam met naam bestaat al, daarna volle capaciteit met reservering is vol. Voeg anders achteraan toe en geef het nieuwe aantal deelnemers terug. Elke afwijzing bewaart de lijst.
3
Annuleren zonder onbedoelde wijzigingen
Maak cancel(name): strip de naam en verwijder haar als zij aanwezig is; geef dan True. Geef bij een onbekende of lege naam False zonder wijziging. Behoud de volgorde van de overblijvers en maak de vrijgekomen plaats weer bruikbaar.
4
Een actuele property en zelfstandige momentopnamen
Maak remaining als leesproperty: capacity min het huidige aantal deelnemers. Maak snapshot() die een nieuwe lijst met de huidige deelnemers in volgorde teruggeeft. Wijzigingen aan ontvangen lijsten raken de reservering niet; twee reserveringen blijven onafhankelijk. Een reservering met capaciteit nul blijft vol.
Onthoud dit
Een samenhangend model houdt zijn beginvoorwaarden en handelingen bij elkaar.
Valideer vóór een wijziging en behoud de toestand bij een afwijzing.
Geef een zelfstandige momentopname wanneer de aanroeper interne lijsten niet mag wijzigen.
Hierna beschrijf je scherper welke waarden en gedragingen functies en objecten van elkaar verwachten.