1. 设计模式概述与分类意义
设计模式是面向对象软件设计中反复出现问题的经典解决方案。作为C++开发者,掌握设计模式的分类体系能够帮助我们快速定位问题场景并选择合适的解决方案。设计模式分类的核心价值在于建立问题域与解决方案之间的映射关系,使开发者能够系统性地思考架构设计。
在C++语境下,设计模式的分类尤为重要。由于C++同时支持面向对象编程、泛型编程和函数式编程范式,不同类型的设计模式在不同场景下展现出独特的优势。例如,策略模式在模板元编程中常以policy-based design的形式出现,而访问者模式则广泛应用于AST处理等场景。
2. 经典GoF分类法解析
2.1 创建型模式(Creational Patterns)
创建型模式抽象了对象实例化过程,使系统不依赖于具体类的创建细节。C++特有的语言特性为这些模式带来了独特实现方式:
-
工厂方法模式(Factory Method):
- 通过虚函数实现多态创建
- 典型应用:Qt框架中的QWidget派生体系
cpp复制class Document { public: virtual void save() = 0; }; class PdfDocument : public Document { public: void save() override { /* PDF保存逻辑 */ } }; class Creator { public: virtual Document* createDocument() = 0; }; class PdfCreator : public Creator { public: Document* createDocument() override { return new PdfDocument(); } }; -
抽象工厂模式(Abstract Factory):
- 常用于跨平台UI库开发
- 结合RAII技术保证资源安全
cpp复制class Button { public: virtual void render() = 0; }; class WinButton : public Button { /*...*/ }; class MacButton : public Button { /*...*/ }; class GUIFactory { public: virtual Button* createButton() = 0; }; class WinFactory : public GUIFactory { public: Button* createButton() override { return new WinButton(); } }; -
建造者模式(Builder):
- 适用于复杂对象的分步构建
- 现代C++常用流式接口(fluent interface)
cpp复制class Pizza { // 复杂构建逻辑 }; class PizzaBuilder { public: PizzaBuilder& setSize(Size s) { /*...*/ return *this; } PizzaBuilder& addTopping(Topping t) { /*...*/ return *this; } Pizza build() { return std::move(pizza); } private: Pizza pizza; }; // 使用示例 Pizza p = PizzaBuilder().setSize(Large).addTopping(Pepperoni).build(); -
原型模式(Prototype):
- 通过拷贝构造函数实现对象克隆
- 需注意深拷贝与浅拷贝问题
-
单例模式(Singleton):
- C++11后推荐使用Meyer's Singleton
- 线程安全的现代实现:
cpp复制class Singleton { public: static Singleton& instance() { static Singleton inst; return inst; } private: Singleton() = default; };
2.2 结构型模式(Structural Patterns)
结构型模式关注类和对象的组合方式,在C++中常涉及指针、引用和模板等特性:
-
适配器模式(Adapter):
- 使不兼容接口协同工作
- 可分为类适配器(继承)和对象适配器(组合)
cpp复制// 对象适配器示例 class LegacyRect { public: void oldDraw() { /*...*/ } }; class Shape { public: virtual void draw() = 0; }; class RectAdapter : public Shape { public: RectAdapter(LegacyRect* r) : rect(r) {} void draw() override { rect->oldDraw(); } private: LegacyRect* rect; }; -
桥接模式(Bridge):
- 分离抽象与实现
- 现代C++常用Pimpl惯用法
cpp复制// Pimpl实现 class WindowImpl { public: virtual void draw() = 0; }; class Window { std::unique_ptr<WindowImpl> impl; public: void draw() { impl->draw(); } }; -
组合模式(Composite):
- 处理树形结构
- STL容器适配器的设计思想
-
装饰器模式(Decorator):
- 运行时动态添加功能
- 与C++模板元编程结合
cpp复制template <typename T> class LoggingDecorator : public T { public: void operation() { logBefore(); T::operation(); logAfter(); } }; -
外观模式(Facade):
- 简化复杂子系统接口
- 常用于库设计
-
享元模式(Flyweight):
- 共享细粒度对象
- 结合对象池技术优化性能
-
代理模式(Proxy):
- 控制对象访问
- 智能指针是典型应用
2.3 行为型模式(Behavioral Patterns)
行为型模式定义对象间通信方式,C++实现时需考虑对象生命周期管理:
-
责任链模式(Chain of Responsibility):
- 处理请求的链式传递
- 事件处理系统的常见结构
-
命令模式(Command):
- 将请求封装为对象
- 支持撤销/重做操作
cpp复制class Command { public: virtual void execute() = 0; virtual void undo() = 0; }; class Invoker { std::stack<std::unique_ptr<Command>> history; public: void executeCommand(std::unique_ptr<Command> cmd) { cmd->execute(); history.push(std::move(cmd)); } }; -
解释器模式(Interpreter):
- 定义语法表示
- 常用于DSL实现
-
迭代器模式(Iterator):
- STL迭代器设计
- 范围for循环的基础
-
中介者模式(Mediator):
- 减少对象间直接耦合
- GUI事件调度典型应用
-
备忘录模式(Memento):
- 捕获对象状态
- 实现撤销机制
-
观察者模式(Observer):
- 发布-订阅机制
- 现代C++信号槽实现
cpp复制template <typename... Args> class Signal { std::vector<std::function<void(Args...)>> slots; public: void connect(std::function<void(Args...)> f) { slots.push_back(f); } void emit(Args... args) { for(auto& slot : slots) slot(args...); } }; -
状态模式(State):
- 封装状态相关行为
- 有限状态机实现
-
策略模式(Strategy):
- 算法族封装
- 常与模板结合
cpp复制template <typename SortingStrategy> class Sorter { SortingStrategy strategy; public: void sort(Container& c) { strategy(c); } }; -
模板方法模式(Template Method):
- 算法骨架定义
- 通过虚函数实现扩展点
-
访问者模式(Visitor):
- 分离算法与数据结构
- AST处理的经典模式
cpp复制class Visitor { public: virtual void visit(ElementA&) = 0; virtual void visit(ElementB&) = 0; }; class Element { public: virtual void accept(Visitor& v) = 0; };
3. 现代C++设计模式变体
3.1 基于模板的模式实现
现代C++中,许多经典模式可通过模板元编程实现编译期多态:
-
策略模式变体:
cpp复制template <typename DrawStrategy> class Circle { DrawStrategy drawer; public: void draw() { drawer(*this); } }; struct OpenGLDrawer { void operator()(Circle<OpenGLDrawer>&) { /*...*/ } }; -
CRTP模式(Curiously Recurring Template Pattern):
- 实现静态多态
- 替代部分虚函数场景
cpp复制template <typename Derived> class Base { public: void interface() { static_cast<Derived*>(this)->implementation(); } }; class Derived : public Base<Derived> { public: void implementation() { /*...*/ } };
3.2 函数式编程风格模式
C++11引入的lambda和函数对象使函数式风格模式成为可能:
-
策略模式的函数式实现:
cpp复制using Strategy = std::function<void()>; class Context { Strategy strategy; public: void setStrategy(Strategy s) { strategy = s; } void execute() { strategy(); } }; -
观察者模式的现代实现:
cpp复制class Event { std::vector<std::function<void()>> handlers; public: void addHandler(std::function<void()> h) { handlers.push_back(h); } void trigger() { for(auto& h : handlers) h(); } };
4. 设计模式选择与组合实践
4.1 模式选择决策树
-
创建问题:
- 需要控制创建过程 → Builder
- 需要全局唯一实例 → Singleton
- 需要灵活的产品系列 → Abstract Factory
-
结构问题:
- 接口不兼容 → Adapter
- 需要透明地添加功能 → Decorator
- 处理树形结构 → Composite
-
行为问题:
- 算法选择 → Strategy
- 状态变化 → State
- 事件通知 → Observer
4.2 常见模式组合
-
Composite + Visitor:
- 处理复杂对象结构
- 典型案例:编译器AST处理
-
Observer + Mediator:
- 构建事件驱动系统
- GUI框架常用组合
-
Factory + Prototype:
- 动态对象创建
- 通过注册表管理原型
5. C++特定模式实现技巧
5.1 资源管理最佳实践
-
RAII与模式结合:
- 智能指针在工厂模式中的应用
cpp复制std::unique_ptr<Document> Creator::createDocument() { return std::make_unique<PdfDocument>(); } -
移动语义优化:
- 建造者模式中的高效对象转移
cpp复制Pizza PizzaBuilder::build() { return std::move(pizza); // 移动而非拷贝 }
5.2 多线程环境考量
-
线程安全单例:
- C++11后的最佳实践
cpp复制Singleton& Singleton::instance() { static Singleton inst; return inst; } -
观察者模式的线程安全:
cpp复制void Event::addHandler(std::function<void()> h) { std::lock_guard<std::mutex> lock(mtx); handlers.push_back(h); }
5.3 性能优化策略
-
享元模式的内存优化:
- 使用对象池减少分配开销
cpp复制class FlyweightFactory { std::unordered_map<Key, std::shared_ptr<Flyweight>> pool; public: std::shared_ptr<Flyweight> getFlyweight(const Key& key) { if(!pool.count(key)) { pool[key] = std::make_shared<ConcreteFlyweight>(key); } return pool[key]; } }; -
编译期策略选择:
- 通过模板元编程避免运行时开销
cpp复制template <typename Strategy> void algorithm(Strategy s) { if constexpr(Strategy::optimized) { // 编译期优化路径 } else { // 通用路径 } }
6. 反模式与常见误区
-
单例滥用问题:
- 导致代码紧耦合
- 测试困难
- 替代方案:依赖注入
-
过度设计陷阱:
- 不要为使用模式而使用
- KISS原则优先
-
C++特定注意事项:
- 虚函数开销考量
- 对象切片问题
- 多继承的合理使用
在实际C++项目中,设计模式的应用需要权衡灵活性、性能和维护成本。建议从简单实现开始,随着需求变化逐步引入模式,而非一开始就构建复杂模式体系。
