Realise that Course, Student, and Roster all hold a map of things.
The fix is one generic class — KeyableMap<V extends Keyable> — that captures “I’m a Keyable thing that contains a map of other Keyable things of type V.”
Course extends KeyableMap<Assessment>Student extends KeyableMap<Course>Roster extends KeyableMap<Student>
1. extends vs implements
extends→ inheriting from a class (you get fields + method implementations for free)implements→ fulfilling an interface contract (you get no code, just a promise to provide the methods listed) Both are IS-A
2. implements
KeyableMap promises to provide a getKey() method. The interface is a contract, not code to borrow
3. <V extends keyable>
means V must be Keyable or a subtype
4. Be specific
Course doesnt take an ImmutableMap, it takes in assessment Courses get doesn’t return Maybe<V>, it returns a Maybe<Assessment>
5. ImmutableMap
- Roster “AY1920” has: a
key(“AY1920”) and anImmutableMap<String, Student>with one entry"Tony" → Student("Tony") - Student “Tony” has: a
key(“Tony”) and anImmutableMap<String, Course>with one entry"CS1231" → Course("CS1231") - Course “CS1231” has: a
key(“CS1231”) and anImmutableMap<String, Assessment>with one entry"Test" → Assessment("Test", "A-") - Assessment “Test” has: a
key(“Test”) and agrade(“A-”). No map. It’s the leaf.
The pattern: every KeyableMap has {key, ImmutableMap of children}. Three levels of the same structure.
6. map
.or(() -> ...) → if any step was empty, substitute the “No such record” message
7. The structure
Student "Tony" ← KeyableMap
├── key: "Tony"
└── children: ImmutableMap<String, Course> ← the STORAGE (ImmutableMap)
├── "CS2040" → Course "CS2040" ← a VALUE (which IS a KeyableMap)
│ ├── key: "CS2040"
│ └── children: ImmutableMap<String, Assessment> ← storage again
│ └── "Lab1" → Assessment ← value (leaf, Keyable but not KeyableMap)
└── "CS1231" → Course "CS1231" ← another value (also KeyableMap)
Every Student holds an ImmutableMap. That ImmutableMap contains Courses, which happen to be KeyableMaps themselves. Then each Course holds its own ImmutableMap of Assessments.
The pattern alternates: KeyableMap → ImmutableMap → KeyableMap → ImmutableMap → leaf.