Quiz 15 — Answers¶
Q1 — C, Liskov Substitution. A subtype must be usable wherever its base is expected — its behaviour must honour the base's contract. A subtype that throws where the base promises success violates this, even if it compiles.
Q2 — False. Open/Closed means extend the design without editing existing code — add a new class rather than a new branch. It does not forbid fixing bugs or refactoring. The test is: does adding the next feature change an existing class?
Q3 — A, B, C. A class edited for unrelated reasons (A) violates Single Responsibility; a fat interface most implementers leave empty (B) violates Interface Segregation; a domain class writing SQL (C) violates Dependency Inversion. A class with a single clear responsibility (D) is a good smell, not a bad one.
Q4 —
The Regular policy returns the base price; Member returns 90%. The context does not
change — only the policy object does. That is the Strategy pattern, and it satisfies
Dependency Inversion: the caller depends on the Pricing abstraction.
Q5 —
WithMilk wraps Coffee and adds " + milk" and 0.5. This is the Decorator pattern:
behaviour is composed at run time by wrapping, instead of by subclassing every combination.
Q6 — s is a local Summary; returning &s returns the address of an object destroyed
at the end of makeReport, so r->render() reads freed storage — undefined behaviour. Fix
by returning an owning smart pointer:
std::unique_ptr<Report> makeReport(const std::string& kind) {
if (kind == "summary") return std::make_unique<Summary>();
return nullptr;
}
Q7 — It violates the Single Responsibility Principle. Three distinct reasons it
changes: the validation rules, the tax rules, the persistence schema (or the receipt
format, or the email wording — any three genuine ones). Each is a separate concern that
should move to its own class, with OrderService coordinating them.
Q8 — High-level modules should depend on abstractions, not on the concrete details of low-level modules; both should depend on the abstraction. In practice: depend on an interface, and let the implementation be substituted. (In C++, an abstract base class is the abstraction.)
Q9 — Observer interface with one update(event) method. Two safety rules:
(1) unsubscription must be safe even if it happens during a notification — for example
the subject hands back a token/handle, or defers removals until the loop finishes; and
(2) ownership — the subject does not own its observers. The owner is the caller, and an
observer must unsubscribe before it is destroyed. Without those rules, a notification can
call into a destroyed observer.
Q10 — A sign: a pattern whose only effect is an extra layer with a single implementation and no second variant in sight — a "strategy" with one strategy, a "factory" that always returns the same class. The cost: more types to read, more indirection to follow, and a harder-to-change design where a plain function would have done. Patterns exist to hold variation; if there is no variation, they are decoration.
Marking. One point per question (Q3 all-or-nothing). Then read Marking Yourself.