Summary - Design patterns
- C++ course
- Advanced
- Lesson 36/83
- 5 min
Combine Singleton, Factory and Strategy to write a payment system.
Summary: combining patterns
In this summary you will combine three patterns in a payment system. You will use Singleton for a single logger, Factory for a method that produces the requested discount type, and Strategy for different discount algorithms.
The Logger must be a single instance because all payments write to the same source. The Discount abstract class is the discount strategy; NoDiscount and TenPercent subclasses apply different algorithms. The createDiscount("ten") call returns the right strategy. The patterns work together: Factory builds Strategy, Singleton logs.
Practice Write the payment system
Define a Logger Singleton with a log(const std::string&) method that prints std::cout << msg;. An abstract Discount class has virtual int apply(int price) const = 0;. NoDiscount returns the price unchanged; TenPercent returns price - price / 10. A createDiscount(const std::string&) Factory method returns TenPercent for "ten". In main compute a 100 unit price with 10 percent discount and log it (output 90).
Starter code
#include <iostream>
#include <memory>
#include <string>
// Define the Logger Singleton class
// Define the Discount abstract class and NoDiscount/TenPercent classes
// Add the createDiscount Factory method
int main() {
// Compute a 100 unit price with TenPercent, log it
return 0;
}Sample solution
#include <iostream>
#include <memory>
#include <string>
class Logger {
public:
static Logger& instance() {
static Logger l;
return l;
}
void log(const std::string& msg) { std::cout << msg; }
private:
Logger() = default;
};
class Discount {
public:
virtual ~Discount() = default;
virtual int apply(int price) const = 0;
};
class NoDiscount : public Discount {
public:
int apply(int price) const override { return price; }
};
class TenPercent : public Discount {
public:
int apply(int price) const override { return price - price / 10; }
};
std::unique_ptr<Discount> createDiscount(const std::string& type) {
if (type == "ten") return std::make_unique<TenPercent>();
return std::make_unique<NoDiscount>();
}
int main() {
auto d = createDiscount("ten");
int total = d->apply(100);
Logger::instance().log(std::to_string(total));
return 0;
}Expected output
90
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Why is the Logger a Singleton in this system?
- To run faster
- So all payments write to the same source Correct answer
- To use less memory
- To be compatible with the Factory
Explanation: Singleton gives one logger; all records go to the same place.
2 Match the pattern to its role
| Term | Meaning |
|---|---|
Logger (Singleton) |
Single logger |
createDiscount (Factory) |
Builds a strategy |
class Discount (Strategy) |
Discount algorithm |
TenPercent |
Concrete strategy |
3 Complete the createDiscount call
auto d = ____("ten");
auto d = createDiscount("ten");
Explanation: createDiscount is the Factory method; it builds a strategy.