Abschlussprojekt: Eine gemeinschaftliche Leihbibliothek · Übung
Die erste Zusammenarbeit der Objekte skizzieren
Zeichne das Bild, bevor du die interessanten Methoden schreibst. Nicht unbedingt auf Papier, aber irgendwo: Die Form, die du jetzt wählst, ist die Umgebung für jede spätere Lektion.
Ein Diagramm, vier Kästen
Library
| owns the catalog -> Book, Game
| owns the members -> Member
| owns the active loans -> Loan
Alle Pfeile zeigen in dieselbe Richtung. Das ist der Entwurf. Library kennt Gegenstände, Mitglieder und Ausleihen. Keines davon kennt Library.
Kapitel 6 lieferte den Grund: Eine erforderliche Abhängigkeit in die Gegenrichtung erschwert es, die Objekte getrennt aufzubauen und zu testen. Würde Member in seinem Konstruktor eine Bibliothek verlangen, müsste ein Test der Mitgliedervalidierung ebenfalls eine bereitstellen. Dieses Projekt hat keine Mitgliedsoperation, die diese Abhängigkeit benötigt.

Kapitel 10 nennt diese Form Abhängigkeitsrichtung. Sie einseitig zu halten trägt wesentlich dazu bei, dass ein kleines System handhabbar bleibt.
Eine Sammlung verwalten heißt, ihre Regeln zu verwalten
Library hält drei Sammlungen. Sie zu halten ist nicht das Interessante. Zu entscheiden, was hineindarf, ist es.
Zwei Regeln gelten von Anfang an. Beide ergeben sich aus der Schnittstellenzusage:
Doppelte Kennungen für Gegenstände und Mitglieder werden abgelehnt.
Eine ID muss genau eine Sache bedeuten. Sonst ist checkout("b1", ...) mehrdeutig, und die gesamte Zusage zerfällt. Deshalb sind add_item und register_member kein blindes Anhängen. Sie bewachen den Zugang zu ihren Sammlungen.
Damit sind sie die ersten echten Methoden, die sich zu schreiben lohnen, und die erste Stelle, an der die vorgegebenen Ausnahmen eingesetzt werden:
from errors import LibraryError
def add_item(self, item):
if item.item_id in self._items:
raise LibraryError(f"item {item.item_id!r} is already in the catalog")
...
Das Argument aus Kapitel 12 gilt unverändert: Ablehnen gehört zur Zusage der Methode und ist kein Zufall.
Warum ein Dictionary mit IDs als Schlüsseln
Die Schnittstelle gibt dir Kennungen. checkout(item_id, member_id, checkout_day) erhält einen String und muss den Gegenstand finden.
Eine Liste würde jedes Mal eine Suche verlangen. Noch schlimmer: Auch „Ist diese ID bereits vergeben?“ müsste durch Durchsuchen beantwortet werden. Ein Dictionary mit der ID als Schlüssel sagt genau, was du meinst: ein Gegenstand pro ID. Die Prüfung auf ein Duplikat verwendet dasselbe Nachschlagen wie der Zugriff.
self._items = {}
self._members = {}
self._loans = {}
Der führende Unterstrich folgt der Konvention aus Kapitel 5. Das ist die interne Verwaltung der Bibliothek und kein Teil ihrer Zusage. Lektion 6 macht die Inhalte vorsichtig zugänglich, über Methoden, die Kopien herausgeben.
Warum hält Member keine Referenz auf die zugehörige Library?
Was du jetzt baust
Gib Library in __init__ seine drei Sammlungen. Mache aus register_member und add_item echte Methoden, die Einträge hinzufügen und wiederholte IDs ablehnen.
Die anderen fünf bleiben unverändert. Ein Abschlussprojekt entsteht in einer sinnvollen Reihenfolge. Eine Klasse, die zur Hälfte aus Platzhaltern besteht, ist in Ordnung, solange du sagen kannst, welche Hälfte das ist.
Aufgabe
Gib Library in library.py seine Sammlungen und die beiden Methoden, die deren Zugang kontrollieren.
__init__ erhält nur self und legt drei leere Dictionarys mit IDs als Schlüsseln an: eines für Gegenstände, eines für Mitglieder und eines für aktive Ausleihen. Gib ihnen Namen mit führendem Unterstrich. Sie dienen der internen Verwaltung der Bibliothek.
add_item(item) speichert den Gegenstand unter seiner item_id und löst LibraryError aus, wenn diese ID bereits im Katalog vorkommt.
register_member(member) tut dasselbe für member.member_id.
Importiere LibraryError aus errors. Jede Ablehnung erhält eine Meldung, die die doppelte ID nennt.
Lass die anderen fünf Methoden weiterhin NotImplementedError auslösen.