Intermediate Interview Bank
Learning Objectives
Answer questions on SOLID, DI, patterns, RAII, Rule of Three/Five/Zero, exceptions, domain modelling and testability.
Prerequisites: Stages 2–3.
Intuition and Definition
Intermediate questions test judgement: *when* to use a principle or pattern and what it costs. Good answers compare alternatives.
Why It Matters
Mid-level roles expect you to make and defend design decisions in code review.
Syntax and Language Notes
Prefer short code sketches over long monologues; name the pattern and show the key interface.
Complete Example
Strategy vs State side by side — a frequent "what's the difference?" question — in one runnable program:
#include <functional>
#include <iostream>
#include <memory>
#include <string>
// STRATEGY: the client picks the algorithm; strategies don't know each other
using Tariff = std::function<double(double kwh)>;
double bill(double kwh, const Tariff& t) { return t(kwh); }
// STATE: the object changes its own behaviour as its state changes
class Charger {
struct State { virtual ~State() = default; virtual std::string plugIn(Charger&) = 0; virtual std::string name() const = 0; };
struct Idle : State { std::string plugIn(Charger& c) override; std::string name() const override { return "Idle"; } };
struct Charging : State { std::string plugIn(Charger&) override { return "already charging"; } std::string name() const override { return "Charging"; } };
std::unique_ptr<State> s_ = std::make_unique<Idle>();
public:
std::string plugIn() { return s_->plugIn(*this); }
std::string state() const { return s_->name(); }
};
std::string Charger::Idle::plugIn(Charger& c) { c.s_ = std::make_unique<Charging>(); return "start charging"; }
int main() {
Tariff flat = [](double k) { return k * 0.30; };
Tariff night = [](double k) { return k * 0.18; };
std::cout << "strategy
…strategy: flat 12, night 7.2
state: Idle -> start charging -> Charging -> already chargingStep-by-Step Walkthrough
The client chooses the tariff strategy; the billing code is unchanged.
The charger replaces its own state object on plugIn; the same call behaves differently afterwards.
Common Mistakes
Reciting SOLID acronyms without an example of a violation and its fix.
Saying "Singleton is fine because it's thread-safe" (thread-safe creation ≠ good design).
Confusing Adapter/Decorator/Proxy.
Treating DI containers as the same thing as dependency inversion.
Trade-offs and Alternatives
Mention the simpler alternative whenever you propose a pattern (a function instead of Strategy, an enum switch instead of State, a constructor instead of Builder).
Real-World Use
These questions mirror design-review discussions on real pull requests.
Practice
Q1. Explain SOLID with one example each.
Answer: SRP: split invoice calculation from PDF rendering. OCP: add a payment provider as a new class instead of editing a switch. LSP: a Square that breaks Rectangle::setWidth violates it. ISP: split Printer/Scanner instead of a fat Machine. DIP: OrderService depends on a PaymentGateway interface it owns (Module 19).
Q2. Give an LSP violation you'd catch in review.
Answer: A subclass that throws NotSupported for a base method, or that requires stricter input than the base contract (Modules 19, 66).
Q3. How does DI improve testability?
Answer: Dependencies arrive through constructors as interfaces, so tests inject fakes for time, storage and I/O and get fast, deterministic tests (Modules 22, 65).
Q4. Factory Method vs Abstract Factory?
Answer: One overridable creation method vs an object creating families of related products (Modules 28–29).
Q5. Strategy vs State?
Answer: Strategy: algorithm chosen by the client, strategies independent. State: behaviour changes with internal state; states drive transitions (Modules 40, 43; example above).
Q6. Adapter vs Decorator vs Proxy?
Answer: Adapter changes an interface; Decorator keeps it and adds behaviour (stackable); Proxy keeps it and controls access (Modules 33, 36, 39).
Q7. What can go wrong with Observer?
Answer: Lapsed-listener leaks, dangling observers, reentrancy, ordering assumptions, slow observers, thread safety (Module 41).
Q8. Singleton drawbacks?
Answer: Global access hides dependencies, hurts testability, shares mutable state, complicates concurrency and shutdown; prefer DI of one instance (Module 27).
Q9. Virtual dispatch cost?
Answer: A vptr per object, an indirect call that's hard to inline, possible cache misses; usually negligible except in hot loops (Module 55).
Q10. Generics vs inheritance for reuse?
Answer: Generics reuse algorithms across types with static checking and no dispatch cost; inheritance shares behaviour through a base and enables heterogeneous run-time collections (Module 17).
Q11. What is RAII?
Answer: Tying resource lifetime to object lifetime: acquire in the constructor, release in the destructor, so cleanup happens on every path including exceptions (Module 13).
Q12. Rule of Three/Five/Zero?
Answer: If you define a destructor or copy operation you likely need the others (Three), plus moves (Five); best to need none by using RAII members (Zero) (Module 12).
Q13. How do you design exceptions in a library?
Answer: A small hierarchy rooted in a library base type, thrown for failures callers can't prevent; expected failures as result types; document guarantees; never throw from destructors; catch by reference (Modules 14, 63).
Q14. Entity vs value object?
Answer: Entity: identity persists through change; value object: defined by attributes, immutable, compared by value (Module 18).
Q15. What makes a class testable?
Answer: Explicit dependencies, deterministic behaviour, small interfaces, observable results, no hidden globals (Modules 64, 67).
Interview Question
Q1. "Refactor a class that creates its own database connection and sends emails inside business logic."
Answer: Introduce interfaces (OrderRepository, Notifier) owned by the service, inject them through the constructor, move the business rule into a pure method or domain object, add tests with fakes, and wire real adapters at the composition root (Modules 19, 22, 54).
Quick Quiz
Q1. Which SOLID principle is about behavioural substitutability?
Answer: Liskov Substitution.
Q2. RAII guarantees release on which paths?
Answer: All of them — normal return, early return and exceptions.
Q3. Is a DI container required for DI?
Answer: No — manual constructor injection is DI.
Summary
Show judgement: when, why, and what it costs; compare with simpler options.
Related: Stages 2–3.