Courses / AOOP / Week 4

CO2 Week 4 of 12

One contract, many implementations

By Thursday one shared test suite judges every allocator, a deliberately broken "saboteur" allocator is caught by it, and the fat parking interface is split into role interfaces.

Requirements: FR3NFR2

Lecture topics

  • Interfaces, abstract classes, sealed types, and role interfaces.
  • Shared contract tests and the SpotAllocator example.

Skill focus

Spot substitutability violations and propose a safer interface.

Lab manual program

Lab 6: Method Contracts and Contract Testing

Aim: Test that every allocator returns an available spot, or -1 when the parking lot is full.

  1. Document the SpotAllocator method contract.
  2. Implement the contract-checking method for partly free and full parking arrays.
  3. Write a second allocator and run the same contract test without changing the test.

Submit the Java source, the console output, and 3–5 lines explaining the concept.

Thread: Monday's practical turns last week's contract into a reusable contract test and runs last Thursday's five LSP violators against it → Tuesday's skill block splits a fat interface into role interfaces and builds a contract checklist → Wednesday's lecture explains when to use an interface, an abstract class or a sealed type, and why contract tests work → Thursday's skill block reads real JDK errors and names the broken clause.

Practical — P4: Liskov substitution and contract testing

Folded in from the lab manual: Lab 6 (document the SpotAllocator contract, a contract‑checking method for partly free and full arrays, a second allocator run through the same test).

Min Step In class Your task
0–10 Build check — Build green.
10–20 Primer "If three allocators share one contract, why write three test classes?" Show the shape below: one contract checker, one abstract test, one subclass per implementation. —
20–40 Step 1: identify violations Give the 5 classes from last Thursday's worksheet as code. Predict which contract clause each breaks.
40–60 Step 2: design the contract checks List the 8 cases below; each maps to one clause of the Javadoc contract. Write SpotAllocatorContract.verify(...) returning a list of violations.
60–90 Step 3: write and repair Real allocators must return no violations; each saboteur must return at least one. Run all; fix any real allocator that fails; record which case caught which saboteur.
90–100 Recap + submit Q: "A new allocator arrives next month. How many new test methods must you write?" (Zero: one subclass.) Commit W4-P4.
# Contract case Clause checked
1 Full lot returns empty Post: empty ⇔ nothing fits
2 Only incompatible spots free (BIKE, all COMPACT) returns empty Post: fits type
3 Partly free lot returns a FREE spot Post (b)
4 Returned spot fits the vehicle type Post (c)
5 Returned spot is the same object as one in the input Post (a)
6 No spot's status changes during choose Frame
7 type == null throws NullPointerException Pre
8 Empty list returns empty Post
public abstract class SpotAllocatorContractTest {
    protected abstract SpotAllocator create();

    @Test void satisfiesContract() {
        assertEquals(List.of(), SpotAllocatorContract.verify(create()));
    }
}
class FirstAvailableAllocatorTest extends SpotAllocatorContractTest {
    protected SpotAllocator create() { return new FirstAvailableAllocator(); }
}
class SaboteurTest {
    @Test void contractCatchesReservedFirstAllocator() {
        assertFalse(SpotAllocatorContract.verify(new ReservedFirstAllocator()).isEmpty());
    }
}

Acceptance checks: one abstract test, ≥ 3 real subclasses, all green; ≥ 3 saboteurs each caught; docs/week04/saboteur-log.md says which case caught which saboteur.

Deliverable (P): commit W4-P4, test report screenshot, saboteur log.

Skill A — S7: role interfaces and shared contract‑test suites

Min Step In class Your task
0–10 Do‑now "List the methods a gate kiosk actually calls." List them.
10–20 Primer Same system, three callers: gate kiosk, mobile app, admin dashboard. Each needs a different slice. —
20–40 Step 1: role interfaces Map each caller to the methods it uses. Draw a caller × method matrix; derive role interfaces.
40–60 Step 2: contract cases For FeeCalculator and SpotAllocator, list cases every implementation must pass. Write the checklist.
60–90 Step 3: apply to two implementations Teams apply the FeeCalculator checklist to two pricing ideas (flat hourly; first 30 minutes free) on paper, then code one. Record pass/fail; commit the FeeCalculator contract test.
90–100 Recap + review Each team names one case the other team missed. Review.

Deliverable (S7): docs/week04/role-interfaces.md (matrix + interfaces) and the reusable contract checklist; UML class diagram of the allocator hierarchy (diagram of the week).

Lecture — L7 + L8: interface, abstract class or sealed; role interfaces; contract tests

Min Step In class Your task
0–10 Do‑now "Should BookingState be an interface, an abstract class, or something else?" One‑line answer.
10–15 Hook Show Monday's saboteur log from one team: the test suite caught bugs nobody hand‑checked. —
15–30 Concept A: choose by cost Interface: any class may implement it; cost: cannot enforce shared invariants or hold state (use for seams such as SpotAllocator, PaymentGateway). Abstract class: shares code and state; cost: one parent only, subclasses depend on base internals. Sealed: closed, known set; cost: adding a variant edits the declaration (use for domain alternatives such as BookingState, PaymentOutcome). Write each cost in one sentence.
30–50 Apply A For 6 Smart Parking types (SpotAllocator, FeePolicy, BookingState, PaymentGateway, ParkingSpot variants, Notifier), teams pick interface, abstract or sealed and give the cost they accept. Decide and justify.
50–55 Bridge "Your ParkingOperations interface has 6 methods. How big is a fake for a test?" Answer.
55–70 Concept B: role interfaces and contract tests Interface segregation argued as a testing principle: a test double for a role interface implements 1 method, not 6. Contract tests: one suite judges every implementation; a saboteur proves the suite has teeth. Notes.
70–90 Apply B Split ParkingOperations (allocate, release, price, pay, notify, report) into role interfaces on the board; write the contract‑test skeleton for FeeCalculator. Draw and write.
90–100 Recap Q1: When is sealed better than an interface? Q2: Why does a contract suite need a saboteur? Q3: Name 3 role interfaces in our system. Answer.

Deliverable (L): the type‑choice table with costs, and the role‑interface split.

Skill B — S8: diagnosing JDK errors caused by contract violations

Min Step In class Your task
0–10 Do‑now "Does @Override change what the program does?" Answer.
10–20 Primer Compile‑time errors tell you the signature contract is broken; run‑time exceptions tell you a behavioural clause is broken. The stack trace's top frame in your code shows who broke it. —
20–40 Step 1: compile errors Snippets 1–4 below. Compile, read the message, name the broken rule.
40–60 Step 2: run‑time errors Snippets 5–7. Run, read the trace, decide caller or implementer.
60–90 Step 3: fix and rerun All fixes must pass the shared contract suite from Monday. Fix each; rerun the suite.
90–100 Recap + submit One team explains one error end to end. Submit.

Worksheet: fill in the blank cells yourself, then compare with your team.

# Broken code (inside an allocator) What the JDK reports (abbreviated) Who is at fault
1 choose(VehicleType t, ArrayList<ParkingSpot> s)
2 Method declared without public
3 choose(...) throws IOException
4 Returns List<ParkingSpot>
5 Calls spots.remove(chosen) on List.of(...)
6 Removes from the list inside a for‑each loop
7 Caller passes type = null

Deliverable (S8): docs/week04/error-diagnosis.md with error, broken clause, fault owner and fix for all 7, plus the corrected code passing the contract suite.

Saved in this browser only.