ooad1-9 Exercise 3: An Object Diagram of a Refused Loan ============================================================= ex3.py (needs objectdiagram.py and the library package from the chapter folder; run from there): """Exercise 3: an object diagram of a situation: a junior member at the loan limit asks for a fourth book. Run from the chapter folder: py ex3/ex3.py""" import pathlib import sys from datetime import date HERE = pathlib.Path(__file__).resolve().parent.parent sys.path.insert(0, str(HERE)) from library.application import LoanDesk # noqa: E402 from library.domain import Copy, Member, Refusal # noqa: E402 from library.infrastructure import InMemoryCatalogue # noqa: E402 from objectdiagram import walk # noqa: E402 catalogue = InMemoryCatalogue([Member("J1", date(2027, 1, 1), "junior")], [Copy(f"B{i}") for i in range(1, 5)]) desk = LoanDesk(catalogue) for code in ("B1", "B2", "B3"): desk.borrow("J1", code, date(2026, 10, 10)) try: desk.borrow("J1", "B4", date(2026, 10, 11)) except Refusal as e: print("fourth loan refused:", e) member = catalogue.member("J1") print("open loans:", len(member.open_loans()), "| copies on loan:", sorted(c.barcode for c in catalogue.copies.values() if c.on_loan)) text = walk([member, catalogue.copy("B4")]) (pathlib.Path(__file__).parent / "limit.object.puml").write_text(text, encoding="utf8") print() print(text) Run with: py ex3/ex3.py Output: fourth loan refused: loan limit reached open loans: 3 | copies on loan: ['B1', 'B2', 'B3'] @startuml scale 1.2 hide empty members object "j1 : Member" as member_0 { card = J1 expires_on = 2027-01-01 kind_name = junior fines_pence = 0 } object "b4 : Copy" as copy_1 { barcode = B4 on_loan = False } object "b1 : Loan" as loan_2 { barcode = B1 borrowed_on = 2026-10-10 due_on = 2026-10-31 returned_on = None } object "b2 : Loan" as loan_3 { barcode = B2 borrowed_on = 2026-10-10 due_on = 2026-10-31 returned_on = None } object "b3 : Loan" as loan_4 { barcode = B3 borrowed_on = 2026-10-10 due_on = 2026-10-31 returned_on = None } member_0 --> loan_2 : loans member_0 --> loan_3 : loans member_0 --> loan_4 : loans @enduml What the diagram shows: member J1 (junior) with three loans, none returned; and the fourth copy, B4, still on the shelf (on_loan = False). The refusal left no trace in the objects: nothing was created or changed. What it cannot show: the refusal itself (an object diagram is one moment, so it shows the state that makes the refusal inevitable, three open loans against a limit of 3, but not the event); that the limit is 3 (the junior's loan limit lives in the kind object, which the diagram does not include because the member holds only its name, kind_name); and why B1 to B3 are not drawn (the loans refer to them by barcode, not by link). WHY THIS WORKS AS AN ANSWER --------------------------- It is generated from the real objects after the real refusal, so it cannot show a situation the code does not allow. The omissions listed are the useful part: each is a question a reader will ask, and each points at a different diagram (a sequence diagram for the event, the class diagram for the limit).