第22天:设计模式
学习目标
学习常用的设计模式,掌握面向对象设计的最佳实践,提高代码的可维护性和可扩展性。
学习资源链接
📚 官方文档和教程
🎥 视频教程
📖 深入阅读
学习内容
1. 单例模式 (Singleton Pattern)
- 概念:确保一个类只有一个实例,并提供全局访问点
- 适用场景:配置管理、日志系统、数据库连接池
- 实现方式:
- 现代C++实现:使用std::call_once和std::once_flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Singleton { private: static std::once_flag flag; static std::unique_ptr<Singleton> instance; Singleton() = default; public: static Singleton& getInstance() { std::call_once(flag, []() { instance = std::make_unique<Singleton>(); }); return *instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
|
2. 工厂模式 (Factory Pattern)
- 简单工厂模式:通过工厂类创建对象
- 工厂方法模式:定义创建对象的接口,子类决定实例化哪个类
- 抽象工厂模式:提供创建相关对象家族的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class Product { public: virtual ~Product() = default; virtual void operation() = 0; };
class ConcreteProductA : public Product { public: void operation() override { std::cout << "ConcreteProductA operation\n"; } };
class Factory { public: virtual ~Factory() = default; virtual std::unique_ptr<Product> createProduct() = 0; };
class ConcreteFactoryA : public Factory { public: std::unique_ptr<Product> createProduct() override { return std::make_unique<ConcreteProductA>(); } };
|
3. 观察者模式 (Observer Pattern)
- 概念:定义对象间的一种一对多依赖关系
- 组成:主题(Subject)和观察者(Observer)
- 应用:事件处理系统、MVC架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Observer { public: virtual ~Observer() = default; virtual void update(const std::string& message) = 0; };
class Subject { private: std::vector<Observer*> observers; public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { observers.erase( std::remove(observers.begin(), observers.end(), observer), observers.end() ); } void notify(const std::string& message) { for (auto* observer : observers) { observer->update(message); } } };
|
4. 策略模式 (Strategy Pattern)
- 概念:定义算法家族,分别封装起来,让它们之间可以互相替换
- 优点:算法可以自由切换,避免使用多重条件判断
- 应用:排序算法选择、支付方式选择
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class SortStrategy { public: virtual ~SortStrategy() = default; virtual void sort(std::vector<int>& data) = 0; };
class QuickSort : public SortStrategy { public: void sort(std::vector<int>& data) override { std::sort(data.begin(), data.end()); std::cout << "Quick sort executed\n"; } };
class SortContext { private: std::unique_ptr<SortStrategy> strategy; public: void setStrategy(std::unique_ptr<SortStrategy> newStrategy) { strategy = std::move(newStrategy); } void executeSort(std::vector<int>& data) { if (strategy) { strategy->sort(data); } } };
|
5. RAII模式 (Resource Acquisition Is Initialization)
- 概念:资源获取即初始化
- 原理:利用对象的构造和析构函数管理资源
- 应用:智能指针、文件句柄、互斥锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class FileManager { private: FILE* file; public: explicit FileManager(const char* filename, const char* mode) { file = fopen(filename, mode); if (!file) { throw std::runtime_error("Failed to open file"); } } ~FileManager() { if (file) { fclose(file); } } FileManager(const FileManager&) = delete; FileManager& operator=(const FileManager&) = delete; FileManager(FileManager&& other) noexcept : file(other.file) { other.file = nullptr; } FileManager& operator=(FileManager&& other) noexcept { if (this != &other) { if (file) fclose(file); file = other.file; other.file = nullptr; } return *this; } FILE* get() const { return file; } };
|
实践练习
练习1:实现线程安全的日志系统
使用单例模式设计一个线程安全的日志系统:
- 支持不同日志级别(DEBUG, INFO, WARNING, ERROR)
- 支持输出到文件和控制台
- 线程安全
练习2:图形工厂系统
设计一个图形工厂系统:
- 抽象工厂创建不同类型的图形(圆形、矩形、三角形)
- 每种图形有不同的绘制方法
- 支持扩展新的图形类型
练习3:事件通知系统
实现一个基于观察者模式的事件通知系统:
- 支持多种事件类型
- 观察者可以订阅和取消订阅特定事件
- 事件发生时通知所有相关观察者
练习4:算法策略选择器
创建一个数据处理系统:
- 支持多种排序算法(快速排序、归并排序、堆排序)
- 可以根据数据特征动态选择最优算法
- 支持添加新的排序策略
LeetCode相关题目
设计类题目
- LeetCode 146 - LRU Cache - 使用设计模式实现LRU缓存
- LeetCode 155 - Min Stack - 栈的设计
- LeetCode 208 - Implement Trie - 前缀树设计
- LeetCode 295 - Find Median from Data Stream - 数据结构设计
系统设计题目
- LeetCode 348 - Design Tic-Tac-Toe - 游戏设计
- LeetCode 362 - Design Hit Counter - 计数器设计
- LeetCode 380 - Insert Delete GetRandom O(1) - 数据结构设计
今日总结
通过学习设计模式,你应该掌握:
- 常用设计模式的概念和实现
- 如何选择合适的设计模式解决问题
- RAII模式在C++中的重要性
- 设计模式与现代C++特性的结合
明天预告
明天我们将学习C++性能优化技巧,包括编译器优化、内存优化和算法优化等内容。
返回第四周 | 上一天:第21天 | 下一天:第23天