Giao diện
Design Pattern Implementation
🎯 Mục tiêu
🎯 Sau bài thực hành này, bạn sẽ:
- Implement Singleton thread-safe (Meyer's Singleton)
- Xây dựng Observer pattern cho event system
- Sử dụng Strategy pattern với
std::function
Mô tả bài tập
Design patterns là giải pháp đã chứng minh cho vấn đề thiết kế phổ biến. Bài tập implement 3 patterns hay dùng nhất trong C++ hiện đại.
Yêu cầu
Bài 1: Singleton — Thread-safe Logger
cpp
class Logger {
public:
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
static Logger& getInstance() { /* TODO: Meyer's Singleton */ }
void log(const std::string& level, const std::string& message) {
// TODO: lock_guard + output
}
private:
Logger() = default;
std::mutex logMutex;
};Bài 2: Observer — Event System
cpp
class EventListener {
public:
virtual void onEvent(const std::string& type, const std::string& data) = 0;
virtual ~EventListener() = default;
};
class EventManager {
std::map<std::string, std::vector<EventListener*>> listeners;
public:
void subscribe(const std::string& type, EventListener* l);
void unsubscribe(const std::string& type, EventListener* l);
void notify(const std::string& type, const std::string& data);
};Bài 3: Strategy — Sorting với std::function
cpp
using SortStrategy = std::function<bool(const Product&, const Product&)>;
class ProductSorter {
SortStrategy strategy;
public:
void setStrategy(SortStrategy s) { strategy = std::move(s); }
void sort(std::vector<Product>& products) {
if (strategy) std::sort(products.begin(), products.end(), strategy);
}
};
// Dùng lambda cho từng chiến lược: price, rating, nameGợi ý
Gợi ý Bài 1
Meyer's: static Logger instance; return instance; trong getInstance(). C++11 đảm bảo thread-safe cho local static.
Gợi ý Bài 2
subscribe: push_back. unsubscribe: erase-remove. notify: duyệt listeners[type] gọi onEvent.
Lời giải tham khảo
Xem lời giải
cpp
// Bài 1
Logger& Logger::getInstance() {
static Logger instance;
return instance;
}
void Logger::log(const std::string& level, const std::string& message) {
std::lock_guard<std::mutex> lock(logMutex);
std::cout << "[" << level << "] " << message << std::endl;
}
// Bài 2
void EventManager::subscribe(const std::string& type, EventListener* l) {
listeners[type].push_back(l);
}
void EventManager::unsubscribe(const std::string& type, EventListener* l) {
auto& vec = listeners[type];
vec.erase(std::remove(vec.begin(), vec.end(), l), vec.end());
}
void EventManager::notify(const std::string& type, const std::string& data) {
if (listeners.count(type))
for (auto* l : listeners[type]) l->onEvent(type, data);
}
// Bài 3 — Usage
sorter.setStrategy([](const Product& a, const Product& b) {
return a.price < b.price;
});