0%

Slotproject: een uitleenbibliotheek voor de buurt · oefening

Geef veilige momentopnamen van collecties terug

De bibliotheek heeft drie private dictionaries en niemand kan zien wat erin zit. Twee bewerkingen uit het contract zijn bedoeld om dat op te lossen:

available_items()
active_loans()

De interessante formulering in het contract staat bij de eerste:

available_items() maakt de objecten die nu uitleenbaar zijn toegankelijk zonder veranderbare interne collecties bloot te geven

Die zin is de les.

Laat wijzigingen via de methoden van Library lopen

De drie dictionaries vormen de private administratie van Library. Ze beheren betekent ook beheren wat ermee gebeurt: elke echte wijziging hoort via een methode te lopen die de regels van de bibliotheek afdwingt.

Als available_items self._items zou teruggeven, zou elke aanroeper dit kunnen schrijven:

shelf.available_items()["sneaky"] = a_book

De catalogus zou dan een item erbij krijgen zonder via add_item te gaan, de enige plek waar de regel over dubbele id’s staat. De bewaker uit les 3 zou naast een open zijdeur staan.

Daarom bouwen deze methoden iets nieuws en geven dat terug. Les 2 van hoofdstuk 13 testte precies deze belofte op Quiz.questions(). Hier ga je die ook testen.

Wat je wel en niet teruggeeft

Wees precies over wat “zonder bloot te geven” omvat, want je kunt makkelijk te ver gaan.

De teruggegeven collectie moet een nieuwe lijst zijn, los van de eigen collecties van de bibliotheek. Als een aanroeper iets toevoegt aan wat hij terugkrijgt, verandert er niets aan de bibliotheek.

De items erin zijn de echte Book- en Game-objecten, en dat is de bedoeling. De aanroeper heeft ze nodig: om over de catalogus te rapporteren, moet die titels van echte items lezen. Als je de items zou kopiëren, zou de aanroeper naar verouderde dubbelgangers kijken. Dat is erger.

Dit is een oppervlakkige momentopname: ze beschermt welke objecten bij de collectie horen, niet de veranderbare items erin. Een gewijzigde titel van een item blijft zichtbaar via andere verwijzingen. De item_id is wel belangrijk voor de bibliotheek, dus aanroepers moeten identificatoren na registratie ongewijzigd laten. Een uitgebreidere applicatie zou dat met alleen-lezen-properties kunnen afdwingen. In dit project lopen wijzigingen aan uitleningen en beschikbaarheid via Library en behandelen we geregistreerde identificatoren als vaststaand.

Beschikbaarheid wordt afgeleid, niet opgeslagen

Er is nergens een vlag is_available en die toevoegen zou een fout zijn.

Een item is precies dan beschikbaar wanneer geen actieve uitlening ernaar verwijst:

    def available_items(self):
        return [
            item
            for item_id, item in self._items.items()
            if item_id not in self._loans
        ]

Dit is dezelfde redenering als bij het aantal uitleningen in les 5. Een vlag legt nogmaals iets vast wat de uitleningen al zeggen. Die twee kunnen elkaar tegenspreken: vergeet de vlag bij het terugbrengen aan te passen en een item dat niemand heeft, blijft voorgoed onzichtbaar. Afgeleide toestand kan niet uit de pas gaan lopen, want de waarheid is maar op één plek vastgelegd.

De bibliotheek slaat geen vlag is_available op items op. Wat levert dat op?

Actieve uitleningen

active_loans() past dezelfde belofte toe op de andere collectie: geef de huidige uitleningen terug in een container die je vrij kunt meegeven.

De uitleningen zelf hebben geen bescherming nodig. Ze zijn bevroren, deels met het oog op dit moment gekozen in les 4: een aanroeper kan de echte uitleenobjecten krijgen en er niets aan veranderen. Dat is de opbrengst van een waardeobject. Daarom is active_loans eenvoudiger dan available_items, hoewel ze dezelfde taak uitvoeren.

Opdracht

Implementeer available_items en active_loans in library.py.

available_items() geeft een lijst terug van de itemobjecten die op dat moment niet zijn uitgeleend, in de volgorde waarin ze aan de catalogus zijn toegevoegd.

active_loans() geeft een lijst van de huidige Loan-waarden terug.

Beide geven elke keer een nieuwe lijst terug. Iets toevoegen aan wat een aanroeper terugkrijgt mag de bibliotheek niet veranderen. Geen van beide methoden mag een eigen dictionary van de bibliotheek of een weergave daarvan teruggeven.

Leid beschikbaarheid af uit de uitleningen. Voeg geen beschikbaarheidsvlag toe aan items.

Laat overdue_loans NotImplementedError opwerpen.