Quiz 15 — SOLID and Design Patterns¶
Ten questions on principles that survive change, and on patterns as a way to apply them rather than decorate a design.
Attempt all of them closed-book, then mark yourself against the answers.
Concepts: the five SOLID principles · factory · strategy · observer · decorator · dependency inversion · over-engineering.
Q1. (MCQ) "A subclass must be usable anywhere its base class is expected" is which principle?
- A. Single Responsibility
- B. Open/Closed
- C. Liskov Substitution
- D. Interface Segregation
Q2. (true/false) The Open/Closed Principle means you may never modify an existing class.
Q3. (multiple-select) Which are symptoms of a design problem? Select all that apply.
- A. One class edited for many unrelated reasons
- B. An interface with eleven methods that most implementers leave empty
- C. A domain class that writes SQL directly
- D. A class with a single, clear responsibility
Q4. (predict) Write the two output lines.
#include <iostream>
#include <memory>
class Pricing {
public:
virtual ~Pricing() = default;
virtual double price(double base) const = 0;
};
class Regular : public Pricing {
public:
double price(double base) const override { return base; }
};
class Member : public Pricing {
public:
double price(double base) const override { return base * 0.9; }
};
int main() {
double base = 100.0;
std::unique_ptr<Pricing> policy = std::make_unique<Regular>();
std::cout << policy->price(base) << '\n';
policy = std::make_unique<Member>();
std::cout << policy->price(base) << '\n';
}
Q5. (predict) Write the two output lines.
#include <iostream>
#include <memory>
#include <string>
class Drink {
public:
virtual ~Drink() = default;
virtual std::string description() const = 0;
virtual double cost() const = 0;
};
class Coffee : public Drink {
public:
std::string description() const override { return "coffee"; }
double cost() const override { return 2.0; }
};
class WithMilk : public Drink {
public:
explicit WithMilk(std::unique_ptr<Drink> inner) : inner_(std::move(inner)) {}
std::string description() const override { return inner_->description() + " + milk"; }
double cost() const override { return inner_->cost() + 0.5; }
private:
std::unique_ptr<Drink> inner_;
};
int main() {
std::unique_ptr<Drink> d = std::make_unique<Coffee>();
d = std::make_unique<WithMilk>(std::move(d));
std::cout << d->description() << '\n';
std::cout << d->cost() << '\n';
}
Q6. (debug) The factory returns a pointer to an object that no longer exists. Explain and fix it, stating the return type.
#include <string>
class Report {
public:
virtual ~Report() = default;
virtual void render() const = 0;
};
class Summary : public Report {
public:
void render() const override { }
};
Report* makeReport(const std::string& kind) {
if (kind == "summary") {
Summary s;
return &s;
}
return nullptr;
}
Q7. (analysis) A single OrderService validates, calculates tax, writes to the
database, formats a receipt and sends email. Name the principle it violates and list
three distinct reasons it has to change.
Q8. (short answer) State the Dependency Inversion Principle in one sentence.
Q9. (design) A system raises events and several consumers react; more will be added; one must stop listening at run time. State the observer interface and the two rules — unsubscription and ownership — that make it safe.
Q10. (analysis) Give one sign that a pattern has been applied where it was not needed, and one cost of that mistake.
Scoring: mark yourself with the answers, then read the self-assessment guide.