设计模式
概述
使用设计模式为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
设计原则分类
SOLID原则 是面向对象设计五大基本原则的缩写。
序号 | 名称 | 英文 | 详解 |
---|---|---|---|
1 | 单一职责原则 | Single Responsibility Principle | 一个类只负责一项职责。 |
2 | 开放封闭原则 | Open Close Principle | 对扩展开放,对修改关闭。 |
3 | 里氏替换原则 | Liskov Substitution Principle | 子类可以扩展父类的功能,但不能改变父类原有的功能。 |
4 | 接口隔离原则 | Interface Segregation Principle | 尽量细化角色,同时客户端应该依赖于抽象。 |
5 | 依赖倒置原则 | Dependency Inversion Principle | 1.高层模块不依赖低层模块,两者都依赖抽象。2.抽象不依赖于细节,细节依赖抽象 |
迪米特法则 | Demeter Principle | 尽量减少对其他对象的引用和依赖,从而降低系统的耦合度。 | |
合成复用原则 | Composite | Reuse Principle |
单一职责原则
开放封闭原则
对于扩展类是开放的,对于修改类是封闭的。
考虑一个超市打折的场景。在封装超市系统时,为了遵循开放封闭原则,我们应该预留一个打折接口。 这样,当需要添加新的打折策略时(如直接打8折、买一送一、送优惠券等),我们只需实现新的打折类,并将其传入接口,而无需修改原有的超市系统代码。
具体实现:
- 定义一个打折接口,包含打折的方法。
- 为每种打折策略实现一个具体的打折类,这些类都实现打折接口。
- 在超市系统中,通过依赖注入或策略模式等方式,将具体的打折实现类与超市系统解耦。
- 当需要添加新的打折策略时,只需创建新的打折类,并更新打折策略的选择逻辑,而无需修改超市系统的其他部分。
通过这种方式,超市系统对打折策略的扩展是开放的,而对原有代码的修改是封闭的,从而提高了系统的可维护性和可扩展性。
里氏替换原则
所有引用基类(父类)的地方必须能透明地使用其子类的对象。
当你扩展一个类的时候,应该在不修改调用方法的基础上,将子类的对象作为父类的对象进行传递。
接口隔离原则
客户端不应该依赖它不需要的接口。即一个类对另一个类的依赖应该建立在最小的接口上。
依赖倒置原则
- 高层模块不应该依赖低层模块,二者都应该依赖抽象
- 抽象不应该依赖细节,细节应该依赖抽象
设计模式分类
设计模式 | 作用 | 应用场景 |
---|---|---|
创建型模式 | 解耦对象的创建过程,提高灵活性和复用性 | |
单例模式 | 确保一个类只有一个实例,并提供全局访问点 | 配置文件管理、线程池、日志系统等需要唯一实例的场景。 |
工厂模式 | 简单工厂模式、工厂方法模式、抽象工厂模式 | 数据库连接、插件系统、跨平台组件(如不同操作系统的UI控件) |
建造者模式 | 分步骤构造复杂对象,避免构造函数参数过多 | 构造复杂对象(如SQL查询生成器、游戏角色配置、房屋设计等) |
原型模式 | 通过克隆现有对象来创建新对象,避免重复初始化 | 对象创建成本高(如深拷贝复杂数据结构) |
----- | ----- | ----- |
结构型模式 | 通过组合类或对象形成更大的结构,提升灵活性和可扩展性 | |
适配器模式 | 将不兼容的接口转换为客户端需要的接口 | 整合旧代码、第三方库接口适配 |
桥接模式 | 将抽象部分与实现部分分离,使两者可独立扩展而不互相影响 | 跨平台UI控件开发(如 Windows/Linux 下的按钮绘制逻辑分离)、绘图引擎中形状与颜色解耦 |
组合模式 | 统一处理树形结构的单个对象和组合对象 | 文件系统、UI组件树、菜单嵌套等层次结构 |
装饰器模式 | 动态扩展对象功能,避免继承导致的类爆炸 | 日志增强、权限校验等运行时功能扩展、流处理(加密/压缩装饰器)、中间件(日志记录,权限校验) |
外观模式 | 为复杂子系统提供简化接口 | 封装第三方库、简化模块间调用 |
代理模式 | 为对象提供代理以控制访问(如延迟加载、权限控制) | 远程服务调用、缓存代理、智能指针(如std::shared_ptr)、权限控制 |
享元模式 | 大量相似对象,通过复用减少内存占用 | 棋子、游戏地图、线程池等 |
MVC模式 | 通过分离数据管理、界面展示、用户交互 实现代码分层,降低系统耦合度 | 逻辑与界面解耦,提升可维护性和可扩展性、支持多人协作开发(如前端/后端分工) |
----- | ----- | ----- |
行为型模式 | 优化对象间的通信和职责分配 | |
责任链模式 | 将请求沿处理链传递,直到被某个对象处理 | 日志过滤、请假审批等 |
命令模式 | 将请求封装为对象,支持撤销、队列等操作 | GUI按钮操作、事务管理、宏命令 |
解释器模式 | 定义语言的文法规则,并通过解释器解析和执行表达式 | 数学公式引擎、简单领域特定语言(DSL)实现,如规则引擎语法解析 |
迭代器模式 | 提供统一接口遍历集合元素,隐藏底层数据结构实现 | STL容器遍历、树形结构的深度优先或广度优先遍历 |
中介者模式 | 通过中介对象封装对象间交互,降低直接耦合 | GUI组件通信、分布式系统中的服务协调 |
备忘录模式 | 捕获对象内部状态并存储,支持撤销/恢复操作 | 文本编辑器的历史记录功能(撤销)、游戏存档系统(保存角色状态并支持读档) |
观察者模式 | 一对多的依赖关系,状态变更时自动通知 | 事件处理系统、MVC模型通知视图更新 |
状态模式 | 将对象行为委托给状态对象,避免条件分支 | 游戏角色状态机、订单状态流转 |
策略模式 | 将算法封装为独立对象,支持运行时切换 | 排序算法、支付方式、游戏AI行为策略等可替换逻辑 |
模板方法模式 | 定义算法骨架,子类重写特定步骤 | 框架设计(如std::sort中的自定义比较逻辑) |
访问者模式 | 将算法与对象结构分离,便于新增操作而不修改数据结构 | 编译器抽象语法树(AST)遍历(如类型检查、代码生成)、复杂数据结构的统计或导出(如 XML 节点数据抽取) |
空对象模式 | 提供默认空行为对象替代 nullptr,避免空指针异常 | 日志系统的空日志器(无操作实现,避免条件判断)、未找到数据时返回默认空对象 |
单例模式
- 角色
角色 含义 Singleton 负责确保有且只有一个实例的创建 Instance 单例类的唯一实例,通过单例类本身提供全局访问点的获取
应用场景:线程池、打印机池、数据库连接池等。
饿汉模式
在程序加载时,就实例化一个静态对象。优点是实现简单且线程安全,缺点是可能浪费内存。
懒汉模式
在第一次使用时,才实例化对象。优点是节省内存,缺点是多线程环境下不安全,因此需要考虑线程安全的同步机制。
class Singleton {
private:
static Singleton* instance;
// static mutex m_mutex;
protected:
Singleton() {}
~Singleton() {}
public:
static Singleton* getInstance() {
// if (instance == nullptr) { // B. 【双重检查锁定】加锁后,若指针不为空,则直接返回。无需再次上锁,提高效率。
// m_mutex.lock(); // A. 【加锁方式】虽实现线程安全,但效率低,每次都要加锁解锁
if (instance == nullptr) {
instance = new Singleton();
}
// m_mutex.unlock();
// }
return instance;
}
};
// 1. 饿汉模式
static Singleton* Singleton::instance = new Singleton();
// 2. 懒汉模式
// static Singleton* Singleton::instance = nullptr;
// 获取单例对象
Singleton* obj = Singleton::getInstance();
注意
上述代码从应用角度看,似乎没问题了。 但是由于代码执行的机器指令顺序重排,则上述流程可能仍然存在问题。因此需要C++11的原子变量atomic
。
class Singleton {
//...
static Singleton* getInstance() {
Singleton* temp = instance.load(); // 临时变量,防止多次赋值
if (temp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex); // 【加锁方式2】使用C++11的锁,自动加锁解锁
temp = instance.load();
if (temp == nullptr) {
temp = new Singleton();
instance.store(temp); // 原子操作,保证线程安全
}
}
return instance;
}
// ...
static atomic<Singleton*> instance;
}
aomatic<Singleton*> Singleton::instance;
懒汉模式还有一种通过静态局部对象的实现方法,像C语言那样,在getInstance中定义static Singleton instance,然后返回&instance即可。
由于在编译时,就已经分配了内存空间。因此线程安全。
工厂模式
角色
角色 英文 含义 抽象产品 Product 定义产品的接口。 具体产品 ConcreteProduct 实现抽象产品的接口。 抽象工厂 Factory 定义创建产品的接口。 具体工厂 ConcreteFactory 实现抽象工厂的接口,返回具体产品。 客户端 Client 使用抽象工厂和产品。 分类
名称 作用 简单工厂模式 通过一个工厂类统一创建对象,隐藏具体实现 工厂方法模式 将对象创建延迟到子类,解决扩展性问题 抽象工厂模式 创建一组相关或依赖的对象(如跨平台的UI组件)
简单工厂模式
简单工厂模式,又叫静态工厂模式。它定义一个工厂类,根据传入的参数来返回不同产品的实例。适用于创建对象数目较少且几乎不扩展的情况。
class Shape {
public:
virtual void draw() = 0;
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
std::cout << "Drawing Rectangle" << std::endl;
}
};
enum class ShapeType:char { // C++11的强枚举类型,代替宏定义
CircleShape,
RectangleShape,
};
class ShapeFactory {
public:
// 用字符串做参数也可以,但是不推荐。因为枚举类型更安全、易读、易维护、扩展性好
static Shape* createShape(ShapeType shapeType) {
Shape* shape = nullptr;
switch (shapeType)
case ShapeType::CircleShape:
{
shape = new Circle();
}break;
case ShapeType::RectangleShape:
{
shape = new Rectangle();
}break;
return shape;
}
};
int main() {
Shape* circle = ShapeFactory::createShape(CircleShape);
circle->draw();
delete circle;
Shape* rectangle = ShapeFactory::createShape(RectangleShape);
rectangle->draw();
delete rectangle;
return 0;
}
工厂方法模式
定义了一个创建对象的接口,但由子类决定数理化的是哪一类,适用于同一个类型的多个产品。
class Shape {
public:
virtual void draw() = 0;
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
std::cout << "Drawing Rectangle" << std::endl;
}
};
class ShapeFactory {
public:
virtual Shape* createShape() = 0;
};
class CircleFactory : public ShapeFactory {
public:
Shape* createShape() override {
return new Circle();
}
};
class RectangleFactory : public ShapeFactory {
public:
Shape* createShape() override {
return new Rectangle();
}
};
int main() {
ShapeFactory* circleFactory = new CircleFactory();
Shape* circle = circleFactory->createShape();
circle->draw();
delete circle;
delete circleFactory;
ShapeFactory* rectangleFactory = new RectangleFactory();
Shape* rectangle = rectangleFactory->createShape();
rectangle->draw();
delete rectangle;
delete rectangleFactory;
return 0;
}
抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,适用于多个类型的多个产品
class Shape {
public:
virtual void draw() = 0;
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
std::cout << "Drawing Rectangle" << std::endl;
}
};
class Color {
public:
virtual void fill() = 0;
};
class Red : public Color {
public:
void fill() override {
std::cout << "Filling with Red" << std::endl;
}
};
class Green : public Color {
public:
void fill() override {
std::cout << "Filling with Green" << std::endl;
}
};
class Product {
public:
Product(Shape* shape, Color* color) : m_shape(shape), m_color(color) {}
~Product() { delete m_shape; delete m_color; }
void draw() { m_shape->draw(); m_color->fill(); }
private:
Shape* m_shape;
Color* m_color;
};
class ProductFactory {
public:
virtual Product* createProduct() = 0;
};
class Factory1 : public ProductFactory {
public:
Product* createProduct() override {
return new Product(new Circle(), new Red());
}
};
class Factory2 : public ProductFactory {
public:
Product* createProduct() override {
return new Product(new Rectangle(), new Green());
}
};
int main() {
ProductFactory* factory1 = new Factory1();
Product* product1 = factory1->createProduct();
product1->draw();
delete product1;
delete factory1;
ProductFactory* factory2 = new Factory2();
Product* product2 = factory2->createProduct();
product2->draw();
delete product2;
delete factory2;
return 0;
}
也可以考虑使用智能指针来改进内存管理,并添加异常处理以增强代码的健壮性。
上述代码对应的生产方案
属性 | 工厂1 | 工厂2 | ... |
---|---|---|---|
形状 | 圆形 | 矩形 | ... |
颜色 | 红色 | 绿色 | ... |
当然了,若形状和颜色组合太多,那么工厂类也会越来越多,可以根据实际需求进行优化。 比如若形状的生产和染色工厂是独立的,则可以定义两个工厂类。
建造者模式
又称生成器模式,用于构建一个复杂对象。
角色
角色 英文 含义 抽象建造者 Builder 为创建一个产品对象的各个部件指定抽象接口 具体建造者 ConcreteBuilder 实现抽象建造者的方法,构建和装配各部件 指挥者 Director 负责控制产品构建的整个过程 产品 Product 表示被构建的复杂对象,包含多个部件 客户端 Client 负责使用建造者来构建对象 应用场景
- 对象内部结构复杂
- 对象构造过程需要分多个步骤进行
- 同一个构建过程可以有多个不同的表示(例如不同的配置或选项)
class House {
public:
void setDoor(const std::string& door) {
this->door = door;
}
void setWindow(const std::string& window) {
this->window = window;
}
void setWall(const std::string& wall) {
this->wall = wall;
}
void showHouse() const {
std::cout << "House with:\n";
std::cout << " Door: " << door << "\n";
std::cout << " Window: " << window << "\n";
std::cout << " Wall: " << wall << "\n";
}
private:
std::string door;
std::string window;
std::string wall;
};
class HouseBuilder {
public:
virtual void buildDoor() = 0;
virtual void buildWindow() = 0;
virtual void buildWall() = 0;
virtual House* getResult() = 0;
};
class ConcreteHouseBuilder : public HouseBuilder {
private:
House* house;
public:
ConcreteHouseBuilder() {
house = new House();
}
void buildDoor() override {
house->setDoor("Wooden Door");
}
void buildWindow() override {
house->setWindow("Glass Window");
}
void buildWall() override {
house->setWall("Brick Wall");
}
House* getResult() override {
return house;
}
};
class HouseDirector {
private:
HouseBuilder* builder;
public:
HouseDirector(HouseBuilder* b) {
builder = b;
}
void constructHouse() {
builder->buildDoor();
builder->buildWindow();
builder->buildWall();
}
House* getHouse() {
return builder->getResult();
}
};
int main() {
HouseBuilder* builder = new ConcreteHouseBuilder();
HouseDirector* director = new HouseDirector(builder);
director->constructHouse();
House* house = director->getHouse();
house->showHouse();
delete house;
delete director;
delete builder;
return 0;
}
原型模式
角色
角色 英文 含义 抽象原型类 Prototype 声明一个克隆自身的接口 具体原型类 ConcretePrototype 实现克隆自身的接口 原型管理器 PrototypeManager 负责存储具体原型对象,并可以克隆这些对象 客户端 Client 让原型管理器创建对象,并在必要时对其进行克隆 分类
- 浅克隆(浅复制):只拷贝对象本身和对象的非静态、非自动成员变量,但不拷贝指向其他对象的指针成员。
- 深克隆(深复制):拷贝对象本身和对象引用的所有对象。
#include <iostream>
#include <string>
#include <unordered_map>
// 抽象基类,声明克隆方法
class Clothes {
public:
virtual ~Clothes() {}
virtual Clothes* Clone() const = 0;
virtual void ShowDetails() const = 0;
protected:
std::string color;
std::string material;
};
// 具体衣服类,实现克隆方法和展示细节方法
class Shirt : public Clothes {
public:
Shirt(const std::string& color, const std::string& material)
: color(color), material(material) {}
Clothes* Clone() const override {
return new Shirt(*this);
}
void ShowDetails() const override {
std::cout << "[Shirt] Color: " << color << ", Material: " << material << std::endl;
}
};
class Pants : public Clothes {
public:
Pants(const std::string& color, const std::string& material)
: color(color), material(material) {}
Clothes* Clone() const override {
return new Pants(*this);
}
void ShowDetails() const override {
std::cout << "[Pants] Color: " << color << ", Material: " << material << std::endl;
}
};
// 原型管理器,用于存储和克隆原型对象
class PrototypeManager {
public:
void RegisterPrototype(const std::string& type, Clothes* prototype) {
prototypes[type] = prototype;
}
Clothes* GetClone(const std::string& type) const {
auto it = prototypes.find(type);
if (it != prototypes.end()) {
return it->second->Clone();
}
return nullptr;
}
private:
std::unordered_map<std::string, Clothes*> prototypes;
};
int main() {
// 创建原型对象
Shirt* redShirt = new Shirt("Red", "Cotton");
Pants* bluePants = new Pants("Blue", "Denim");
// 注册原型对象到原型管理器
PrototypeManager manager;
manager.RegisterPrototype("RedShirt", redShirt);
manager.RegisterPrototype("BluePants", bluePants);
// 克隆衣服对象
Clothes* clonedShirt = manager.GetClone("RedShirt");
Clothes* clonedPants = manager.GetClone("BluePants");
// 展示克隆对象的细节
if (clonedShirt) {
clonedShirt->ShowDetails();
}
if (clonedPants) {
clonedPants->ShowDetails();
}
// 清理内存(在实际应用中,应该使用智能指针来管理内存)
delete redShirt;
delete bluePants;
delete clonedShirt;
delete clonedPants;
return 0;
}
其中原型管理器PrototypeManager
并不是必须的,但是它的优势在于:
- 集中管理原型对象,使得克隆过程更加集中和统一
例如图形编辑软件中,有多个图形对象(圆形、三角形、矩形等)原型管理器可以存储这些原型对象,并在需要时提供克隆服务。
- 便于扩展,例如可以添加查找原型对象的功能
例如图形编辑软件需要添加一种新的图形对象(如星形),只需在原型管理器中注册新的原型对象,而无需修改现有的图形创建逻辑。
- 简化客户端代码,使得克隆操作更加简单
例如在图形编辑软件中,如果要克隆一个圆形对象,只需从原型管理器获取“Circle”类型的克隆即可。
- 支持运行时动态添加新的原型对象,而不需要修改客户端代码
例如在游戏开发中,如果可以根据玩家的选择(如法师、刺客等),从原型管理器加载不同的角色原型,而无需在代码中硬编码所有角色的创建逻辑。
适配器模式
主要用于将一个接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。 适配器模式通过引入一个适配器类,在不修改原有类的情况下,实现接口的兼容。
角色
角色 英文 含义 目标接口 Target 定义客户希望使用的接口 待适配者 Adaptee 定义需要被适配的已有接口 适配器 Adapter 实现目标接口,并通过适配者接口与原有系统交互 客户端 Client 使用目标接口,无需关心适配者接口的存在 实现方式
- 类适配器:通过多重继承实现
- 对象适配器:通过组合或聚合实现【推荐】
应用场景
- 充电器适配器:将220V的电源适配为手机充电所需的5V
- 数据库适配器:将旧版数据库接口适配为新版应用所需的接口
继承方式实现适配器模式:
class Target {
public:
virtual void request() = 0;
};
class Adaptee {
public:
void specificRequest() { /* 实现特定功能 */ }
};
class Adapter : public Target, private Adaptee {
public:
void request() override {
specificRequest(); // 通过适配者接口调用原有系统的方法
}
};
int main() {
Target* t = new Adapter(); // 客户端通过目标接口使用适配器
t->request();
delete t;
return 0;
}
对象适配器实现适配器模式:
class Target {
virtual void request() = 0;
};
class Adaptee {
public:
void specificRequest() { /* 实现特定功能 */ }
};
// 使用组合实现适配器模式
class Adapter : public Target {
private:
Adaptee* adaptee_; // 通过成员变量持有适配者对象
public:
Adapter(Adaptee* adaptee) : adaptee_(adaptee) {}
void request() override {
if (adaptee_) {
adaptee_->specificRequest(); // 通过
// 这里可以添加其他逻辑,例如日志记录、安全检查等
}
}
};
int main() {
Adaptee* adaptee = new Adaptee(); // 创建适配者对象
Target* t = new Adapter(adaptee); // 使用适配器包装适配者
t->request();
delete t;
delete adaptee;
return 0;
}
适配器中的成员对象:
- 可以不用指针:当适配逻辑简单、对象轻量且无多态需求时,直接持有对象更安全高效。
- 推荐用指针:若需要多态、动态灵活性或资源控制,优先选择智能指针管理。
桥接模式
桥接模式是一种通过解耦抽象与实现来提升代码灵活性的结构型设计模式。
角色
角色 英文 含义 抽象化 Abstraction 定义抽象类,包含一个对实现化对象的引用 实现化 Implementor 定义实现类,包含具体行为 桥接 Bridge 定义抽象化与实现化的桥梁,通常包含一个指向实现化对象的引用 客户端 Client 通过抽象化接口操纵实现化的具体行为 应用场景
场景 描述 系统需要支持多个独立变化的维度 GUI库中的控件类型 + 操作系统接口 需要避免因继承导致的类层次爆炸 算法与平台的交叉组合、“形状+颜色”通过组合替代继承,减少子类数量 运行时需动态切换实现的场景 如数据库驱动切换 优势
解耦抽象与实现、避免类爆炸、提升可维护性
// 实现层:颜色接口
class Color {
public:
virtual string ApplyColor() = 0;
};
// 具体颜色实现
class Red : public Color {
public:
string ApplyColor() override { return "Red"; }
};
// 抽象层:形状接口
class Shape {
protected:
Color* color_;
public:
Shape(Color* color) : color_(color) {}
virtual void Draw() = 0;
};
// 具体形状实现
class Circle : public Shape {
public:
Circle(Color* color) : Shape(color) {}
void Draw() override {
cout << "Drawing Circle in " << color_->ApplyColor() << endl;
}
};
// 客户端代码
int main() {
Color* red = new Red();
Shape* circle = new Circle(red);
circle->Draw(); // 输出:Drawing Circle in Red
delete circle;
delete red;
return 0;
}
桥接模式与适配器模式的区别:
- 适配器模式:解决接口不兼容问题,适配者已有方法,客户端期望新接口
- 桥接模式:解决多层继承结构问题,抽象与实现分离,运行时动态切换实现,二者解决的问题不同。
桥接模式和工厂模式的区别:
- 工厂模式:用于创建对象,侧重于对象的实例化
- 桥接模式:用于解耦抽象与实现,侧重于对象的结构化设计。
组合模式
组合模式是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次结构。组合使得用户对单个对象和组合对象的使用具有一致性。
角色
角色 英文 含义 抽象构件 Component 定义参加组合对象的接口 树叶构件 Leaf 叶子节点对象,其组合中可以没有子节点 树枝构件 Composite 树枝节点对象,其组合中可以包含子节点 客户端 Client 通过抽象构件接口操纵组合对象,使之与单个对象具有相同的操作方式 应用场景
场景 描述 图形用户界面 窗口包含控件,控件包含按钮、文本框等 文件系统 目录可包含文件或子目录 组织结构 部门包含员工或子部门
// 抽象构件
class Component {
public:
virtual ~Component() = default;
virtual void operation() = 0;
virtual void add(Component* child) {} // 默认空实现
virtual void remove(Component* child) {}
virtual Component* getChild(int index) { return nullptr; }
};
// 叶子节点
class Leaf : public Component {
public:
void operation() override {
std::cout << "Leaf operation\n";
}
};
// 组合节点
class Composite : public Component {
private:
std::vector<Component*> children;
public:
void operation() override {
std::cout << "Composite operation\n";
for (auto* child : children) {
child->operation(); // 递归调用子节点
}
}
void add(Component* child) override {
children.push_back(child);
}
void remove(Component* child) override {
children.erase(std::remove(children.begin(), children.end(), child), children.end());
}
Component* getChild(int index) override {
return (index < children.size()) ? children[index] : nullptr;
}
};
// 客户端代码
int main() {
Composite* root = new Composite();
root->add(new Leaf());
root->add(new Leaf());
Composite* branch1 = new Composite();
branch1->add(new Leaf());
root->add(branch1);
root->operation();
delete root;
return 0;
}
/**
输出:
Composite operation
Leaf operation
Leaf operation
Composite operation
Leaf operation
*/
装饰器模式
装饰器模式的核心思想是用组合代替继承
,动态地为对象添加职责。它通过创建装饰器类来扩展对象的功能,而无需修改对象的结构或创建大量的子类。
- 角色
角色 英文 含义 抽象组件 Component 定义一个对象接口,可以给这些对象动态地添加职责 具体组件 ConcreteComponent 定义一个对象,可以给这个对象添加一些职责 抽象装饰器 Decorator 维持一个指向Component对象的引用,并定义一个与Component接口一致的接口 具体装饰器 ConcreteDecorator 向组件添加职责 客户端 Client 通过装饰器来扩展组件的功能
// 抽象组件
class TextComponent {
public:
virtual ~TextComponent() = default;
virtual std::string getText() const = 0;
};
// 具体组件
class PlainText : public TextComponent {
private:
std::string _text;
public:
PlainText(const std::string& text) : _text(text) {}
std::string getText() const override {
return _text;
}
};
// 抽象装饰器类
class TextDecorator : public TextComponent {
protected:
std::shared_ptr<TextComponent> _component;
public:
TextDecorator(std::shared_ptr<TextComponent> component) : _component(component) {}
std::string getText() const override {
return _component->getText();
}
};
// 具体装饰器类A:加粗文本
class BoldText : public TextDecorator {
public:
BoldText(std::shared_ptr<TextComponent> component) : TextDecorator(component) {}
std::string getText() const override {
return "<b>" + TextDecorator::getText() + "</b>";
}
};
// 具体装饰器类B:斜体文本
class ItalicText : public TextDecorator {
public:
ItalicText(std::shared_ptr<TextComponent> component) : TextDecorator(component) {}
std::string getText() const override {
return "<i>" + TextDecorator::getText() + "</i>";
}
};
int main() {
// 创建一个具体组件对象
std::shared_ptr<TextComponent> plainText = std::make_shared<PlainText>("Hello, World!");
std::cout << "Original Text: " << plainText->getText() << std::endl;
// 使用具体装饰器A(加粗)
std::shared_ptr<TextComponent> boldText = std::make_shared<BoldText>(plainText);
std::cout << "Bold Text: " << boldText->getText() << std::endl;
// 使用具体装饰器B(斜体)
std::shared_ptr<TextComponent> italicBoldText = std::make_shared<ItalicText>(boldText);
std::cout << "Italic Bold Text: " << italicBoldText->getText() << std::endl;
return 0;
}
外观模式
外观模式是一种结构型设计模式,通过提供统一的接口简化复杂子系统的使用,降低客户端与子系统的耦合度。
- 角色
角色 英文 含义 外观 Facade 为多个子系统操作提供一个统一的接口 子系统 Subsystem 包含实现功能的类或模块 客户端 Client 通过外观接口与子系统交互,无需直接调用子系统的类
#include <iostream>
#include <memory>
#include <stdexcept>
// 子系统1:词法分析器
class Scanner {
public:
virtual ~Scanner() = default;
virtual void Scan() {
std::cout << "Scanning source code...\n";
}
};
// 子系统2:语法分析器
class Parser {
public:
virtual ~Parser() = default;
virtual void Parse() {
std::cout << "Parsing tokens to build AST...\n";
}
};
// 子系统3:中间代码生成器
class MidCodeGenerator {
public:
virtual ~MidCodeGenerator() = default;
virtual void GenCode() {
std::cout << "Generating intermediate code (e.g., LLVM IR)...\n";
}
};
struct CompileOptions {
std::string targetPlatform{"x86"};
bool optimize{false};
};
// 子系统4:目标机器码生成器
class MachineCodeGenerator {
public:
virtual ~MachineCodeGenerator() = default;
virtual void GenCode(const CompileOptions& options) {
if (options.targetPlatform == "x86") {
// x86平台机器码生成逻辑
} else if (options.targetPlatform == "ARM") {
// ARM平台机器码生成逻辑
} else {
throw std::runtime_error("Unsupported target platform: " + options.targetPlatform);
}
}
};
class CompilerFacade {
public:
CompilerFacade(
std::shared_ptr<Scanner> scanner = std::make_shared<Scanner>(),
std::shared_ptr<Parser> parser = std::make_shared<Parser>(),
std::shared_ptr<MidCodeGenerator> midGen = std::make_shared<MidCodeGenerator>(),
std::shared_ptr<MachineCodeGenerator> machineGen = std::make_shared<MachineCodeGenerator>()
) : scanner_(std::move(scanner)),
parser_(std::move(parser)),
midCodeGen_(std::move(midGen)),
machineCodeGen_(std::move(machineGen)) {}
void Compile(const CompileOptions& options = CompileOptions{}) {
try {
Initialize();
if (scanner_) scanner_->Scan();
if (parser_) parser_->Parse();
if (midCodeGen_) midCodeGen_->GenCode();
if (machineCodeGen_) machineCodeGen_->GenCode(options);
Cleanup();
} catch (const std::exception& e) {
std::cerr << "Compilation failed: " << e.what() << "\n";
Cleanup();
}
}
private:
void Initialize() {
std::cout << "Initializing compiler...\n";
}
void Cleanup() {
std::cout << "Cleaning up resources...\n";
}
std::shared_ptr<Scanner> scanner_;
std::shared_ptr<Parser> parser_;
std::shared_ptr<MidCodeGenerator> midCodeGen_;
std::shared_ptr<MachineCodeGenerator> machineCodeGen_;
};
int main() {
CompilerFacade compiler;
// 默认编译
compiler.Compile();
// 自定义编译选项
CompileOptions options;
options.targetPlatform = "ARM";
options.optimize = true;
compiler.Compile(options);
return 0;
}
代理模式
代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。
角色
角色 英文 含义 代理 Proxy 控制对原对象的访问,可以过滤和/或修改请求 主题 Subject 定义真实对象和代理对象的公共接口 真实主题 RealSubject 定义代理所代表的对象的接口 客户端 Client 通过代理接口与真实主题交互 适用场景
场景 举例 需要控制访问 权限检查、防火墙规则 优化性能 延迟加载大资源(如图片、数据库连接) 增强功能 添加日志、缓存等非业务逻辑
代理模式与装饰器模式最易混淆,但关键区别在于意图:
代理控制访问,装饰器扩展功能
// 抽象主题:网络访问接口
class NetworkAccess {
public:
virtual void request(const std::string& url) = 0;
virtual ~NetworkAccess() = default;
};
// 真实主题:实际网络操作
class RealNetwork : public NetworkAccess {
public:
void request(const std::string& url) override {
if (url.empty()) {
throw std::invalid_argument("URL cannot be empty");
}
std::cout << "Accessing real network resource: " << url << std::endl;
}
};
// 代理类:控制网络访问
class NetworkProxy : public NetworkAccess {
private:
std::unique_ptr<NetworkAccess> realNetwork;
mutable std::mutex accessMutex;
bool validateAccess(const std::string& url) const {
// 实际实现中应包含更复杂的验证逻辑
return !url.empty() &&
(url.find("https://") == 0 || url.find("http://") == 0);
}
void logAccess(const std::string& url) const {
auto now = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::cout << "[" << std::ctime(&time) << "] Accessed: " << url << std::endl;
}
public:
explicit NetworkProxy(std::unique_ptr<NetworkAccess> network = std::make_unique<RealNetwork>())
: realNetwork(std::move(network)) {}
void request(const std::string& url) override {
std::lock_guard<std::mutex> lock(accessMutex);
if (!validateAccess(url)) {
std::cerr << "Access denied for URL: " << url << std::endl;
return;
}
realNetwork->request(url);
logAccess(url);
}
};
int main() {
NetworkProxy proxy;
proxy.request("https://example.com");
return 0;
}
享元模式
享元模式是一种结构型设计模式,通过共享相似对象减少内存占用和提高性能。 其核心思想是将对象状态分为内部状态(可共享且不可变)和外部状态(不可共享且动态变化),通过工厂管理共享对象的复用
角色
角色 英文 含义 抽象享元 Flyweight 定义了所有具体享元的公共接口 具体享元 ConcreteFlyweight 实现抽象享元类定义的接口 非共享的具体享元 UnsharedConcreteFlyweight 不是所有的情况下都共享的享元子类 享元工厂 FlyweightFactory 创建并管理享元对象 适用场景
场景 举例 大量相似的对象 字符池、图像缓存 频繁创建和销毁的对象 游戏中的子弹、精灵 资源共享的系统 数据库连接池
#include <iostream>
#include <unordered_map>
#include <memory>
#include <string>
struct Position {
int x;
int y;
};
// 抽象享元类
class ChessPiece {
public:
virtual void draw(Position pos) = 0;
virtual ~ChessPiece() = default;
};
// 具体享元类(黑色和白色棋子)
class BlackChess : public ChessPiece {
public:
void draw(Position pos) override {
std::cout << "Black at (" << pos.x << "," << pos.y << ")\n";
}
};
class WhiteChess : public ChessPiece {
public:
void draw(Position pos) override {
std::cout << "White at (" << pos.x << "," << pos.y << ")\n";
}
};
// 享元工厂类
class ChessFactory {
private:
enum class ChessColor { Black, White };
std::unordered_map<ChessColor, std::unique_ptr<ChessPiece>> pool_;
public:
ChessPiece* getChess(const std::string& color) {
ChessColor key = (color == "black") ? ChessColor::Black : ChessColor::White;
if (!pool_.count(key)) {
if (key == ChessColor::Black) {
pool_[key] = std::make_unique<BlackChess>();
} else {
pool_[key] = std::make_unique<WhiteChess>();
}
}
return pool_[key].get();
}
};
// 客户端
int main() {
ChessFactory factory;
auto black1 = factory.getChess("black");
black1->draw({10, 20});
auto black2 = factory.getChess("black");
black2->draw({30, 40});
return 0;
}
MVC模式
MVC模式是一种结构型设计模式,它将软件系统分为三个核心部分:模型(Model)、视图(View)和控制器(Controller)
角色
角色 英文 含义 模型 Model 封装应用数据和业务逻辑 视图 View 负责显示数据,但不包含业务逻辑 控制器 Controller 接收用户输入,调用模型和视图更新数据 适用场景
场景 举例 用户界面设计 图形界面的布局和交互 数据驱动的应用 Web应用的后端逻辑 数据展示 报表生成和数据显示
// Model.hpp - 数据处理核心
#include <QString>
class StringModel {
public:
int calculateLength(const QString& text) {
return text.length(); // 纯业务逻辑处理:ml-citation{ref="1,5" data="citationList"}
}
};
// View.hpp - 界面组件定义
class MainView : public QWidget {
public:
QLineEdit* inputField;
QPushButton* calcButton;
QLabel* resultLabel;
MainView(QWidget* parent = nullptr) {
inputField = new QLineEdit(this);
calcButton = new QPushButton("计算长度", this);
resultLabel = new QLabel("结果:", this);
// 布局设置
inputField->setGeometry(20, 20, 200, 30);
calcButton->setGeometry(20, 60, 100, 30);
resultLabel->setGeometry(20, 100, 200, 30);
}
};
// Controller.hpp - 业务协调者
class Controller : public QObject {
Q_OBJECT
public:
Controller(StringModel* model, MainView* view)
: m_model(model), m_view(view) {
connect(m_view->calcButton, &QPushButton::clicked,
this, &Controller::handleCalculation);
}
private slots:
void handleCalculation() {
QString input = m_view->inputField->text();
int length = m_model->calculateLength(input);
m_view->resultLabel->setText(QString("长度:%1").arg(length));
}
private:
StringModel* m_model;
MainView* m_view;
};
// 程序入口
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 初始化MVC组件
StringModel model;
MainView view;
Controller controller(&model, &view);
view.show();
return app.exec();
}
责任链模式
责任链模式是一种行为设计模式,它允许将请求沿着链传递直到有对象处理该请求。
本质上是链表的访问。
角色
角色 英文 含义 抽象处理者 Handler 定义一个处理请求的接口 具体处理者 ConcreteHandler 实现抽象处理者的接口,并可选择是否将请求传递给链中的下一个处理者 客户端 Client 创建处理者对象并设置链中的下一个处理者 适用场景
场景 举例 多级权限控制系统 报销审批、请假流程 事件过滤机制 游戏输入处理链 异常处理系统 不同处理器捕获特定类型异常
// 抽象处理者类
class Leader {
protected:
std::unique_ptr<Leader> nextLeader; // 使用智能指针管理资源
const int approvalLimit; // 审批限额
public:
explicit Leader(int limit) : approvalLimit(limit) {}
virtual ~Leader() = default;
void setNextLeader(std::unique_ptr<Leader> leader) {
if (leader) {
nextLeader = std::move(leader); // 核心逻辑,确保链的正确构建和传递
}
}
virtual void approveExpense(int amount) {
if (amount <= 0) {
std::cout << "[系统] 无效金额:" << amount << "元" << std::endl;
return;
}
if (amount <= approvalLimit) {
std::cout << "[审批] " << getTitle() << "批准报销:" << amount << "元" << std::endl;
} else if (nextLeader) {
nextLeader->approveExpense(amount);
} else {
std::cout << "[系统] 需要更高权限审批:" << amount << "元" << std::endl;
}
}
virtual std::string getTitle() const = 0;
};
// 具体处理者类
class DepartmentLeader : public Leader {
public:
DepartmentLeader() : Leader(5000) {}
std::string getTitle() const override { return "部门主管"; }
};
class GeneralManager : public Leader {
public:
GeneralManager() : Leader(20000) {}
std::string getTitle() const override { return "总经理"; }
};
// 客户端代码
int main() {
// 构建责任链
auto chain = std::make_unique<DepartmentLeader>();
auto boss = std::make_unique<GeneralManager>();
chain->setNextLeader(std::move(boss));
// 发送请求
chain->approveExpense(3000);
chain->approveExpense(15000);
chain->approveExpense(25000);
chain->approveExpense(0);
chain->approveExpense(-100);
return 0;
}
命令模式
命令模式是一种行为设计模式,它将请求封装为对象,从而允许用户使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销操作。
本质上是发送者与接收者的解耦
角色
角色 英文 含义 命令 Command 声明执行操作的接口 具体命令 ConcreteCommand 封装一个接收者对象,并将调用其操作参数化 调用者 Invoker 负责调用命令对象执行请求 接收者 Receiver 知道如何实现与执行一个请求相关的操作 客户端 Client 创建具体命令对象并设置接收者,然后调用执行操作 适用场景
场景 举例 请求的参数化 撤销操作、事务处理 操作记录日志 命令历史、宏录制 宏命令 宏录制、宏播放 队列请求 异步处理、延迟执行 回调 事件处理、异步编程
// 命令接口
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
};
// 接收者类:灯具
class Light {
public:
virtual ~Light() = default;
void turnOn() const {
std::cout << "Light is ON" << std::endl;
}
void turnOff() const {
std::cout << "Light is OFF" << std::endl;
}
};
// 具体命令:开灯命令
class LightOnCommand : public Command {
std::shared_ptr<Light> light;
public:
explicit LightOnCommand(std::shared_ptr<Light> l) : light(std::move(l)) {
if (!light) {
throw std::invalid_argument("Light cannot be null");
}
}
void execute() override {
try {
light->turnOn();
} catch (const std::exception& e) {
std::cerr << "Error executing LightOnCommand: " << e.what() << std::endl;
throw;
}
}
};
// 具体命令:关灯命令
class LightOffCommand : public Command {
std::shared_ptr<Light> light;
public:
explicit LightOffCommand(std::shared_ptr<Light> l) : light(std::move(l)) {
if (!light) {
throw std::invalid_argument("Light cannot be null");
}
}
void execute() override {
try {
light->turnOff();
} catch (const std::exception& e) {
std::cerr << "Error executing LightOffCommand: " << e.what() << std::endl;
throw;
}
}
};
// 调用者:遥控器
class RemoteControl {
std::unique_ptr<Command> command;
public:
void setCommand(std::unique_ptr<Command> cmd) {
if (!cmd) {
throw std::invalid_argument("Command cannot be null");
}
command = std::move(cmd);
}
void pressButton() const {
if (command) {
command->execute();
} else {
std::cerr << "No command set" << std::endl;
}
}
};
int main() {
try {
// 创建接收者
auto livingRoomLight = std::make_shared<Light>();
// 创建具体命令并绑定接收者
auto lightOn = std::make_unique<LightOnCommand>(livingRoomLight);
auto lightOff = std::make_unique<LightOffCommand>(livingRoomLight);
// 设置调用者
RemoteControl remote;
remote.setCommand(std::move(lightOn));
remote.pressButton();
remote.setCommand(std::move(lightOff));
remote.pressButton();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
解释器模式
解释器模式是一种行为型设计模式,用于构建特定领域语言(DSL)的解释器,将复杂的语法规则分解为可管理的表达式类,并通过组合这些表达式实现语义解析。
适用于需要频繁解析固定文法结构的场景,如数学表达式、正则表达式或业务规则引擎
角色
角色 英文 含义 抽象表达式 AbstractExpression 声明一个抽象的解释操作,这是所有具体表达式类的公共接口 终结符表达式 TerminalExpression 实现与文法中的终结符号相关的解释操作 非终结符表达式 NonterminalExpression 为文法中的非终结符定义解释方法(通常组合其他类型的表达式) 环境类 Context 包含解释器之外的全局信息 客户端 Client 构建或使用解析树,解释文法 适用场景
场景 举例 复杂语言的语法分析 编译器、脚本引擎 自定义查询语言 数据库查询处理器 自然语言理解 语音识别系统 配置文件解析 应用程序设置管理 规则引擎 业务逻辑自动化
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
// 上下文存储变量
struct Context {
std::unordered_map<std::string, int> variables;
};
// 抽象表达式接口
class Expression {
public:
virtual ~Expression() = default;
virtual int interpret(Context& context) = 0;
};
// 终结符表达式:整数常量
class Number : public Expression {
int value;
public:
explicit Number(int v) : value(v) {}
int interpret(Context&) override { return value; }
};
// 终结符表达式:变量
class Variable : public Expression {
std::string name;
public:
explicit Variable(std::string n) : name(std::move(n)) {}
int interpret(Context& context) override {
return context.variables[name];
}
};
// 非终结符表达式:加法
class Add : public Expression {
std::unique_ptr<Expression> left;
std::unique_ptr<Expression> right;
public:
Add(std::unique_ptr<Expression> l, std::unique_ptr<Expression> r)
: left(std::move(l)), right(std::move(r)) {}
int interpret(Context& context) override {
return left->interpret(context) + right->interpret(context);
}
};
// 非终结符表达式:乘法
class Multiply : public Expression {
std::unique_ptr<Expression> left;
std::unique_ptr<Expression> right;
public:
Multiply(std::unique_ptr<Expression> l, std::unique_ptr<Expression> r)
: left(std::move(l)), right(std::move(r)) {}
int interpret(Context& context) override {
return left->interpret(context) * right->interpret(context);
}
};
int main() {
// 初始化上下文
Context context;
context.variables["x"] = 5;
context.variables["y"] = 10;
// 构建表达式树:(x + 3) * (y - 2)
auto expr = std::make_unique<Multiply>(
std::make_unique<Add>(
std::make_unique<Variable>("x"),
std::make_unique<Number>(3)
),
std::make_unique<Add>(
std::make_unique<Variable>("y"),
std::make_unique<Number>(-2) // 用加法实现减法
)
);
// 计算结果:(5+3)*(10-2) = 8*8 = 64
std::cout << "Result: " << expr->interpret(context) << std::endl;
return 0;
}
迭代器模式
迭代器模式是一种行为设计模式,它提供一种方法顺序访问聚合对象中的各个元素,而无需暴露其内部表示。
角色
角色 英文 含义 抽象聚合 Aggregate 定义创建迭代器的接口并提供一个方法来检索第一个迭代器 具体聚合 ConcreteAggregate 实现返回一个特定类型的迭代器的 createIterator() 方法 迭代器 Iterator 定义访问和遍历元素的接口 具体迭代器 ConcreteIterator 跟踪当前位置并知道如何移动到下一个位置 客户端 Client 使用迭代器来遍历聚合的元素 适用场景
- 需要遍历集合但不暴露底层数据结构时
- 提供多种方式遍历同一集合时
- 支持双向或逆向遍历时
- 需要隐藏复杂的数据结构时
#include <iostream>
#include <vector>
// 抽象聚合接口
class Collection {
public:
virtual ~Collection() = default;
virtual Iterator* createIterator() = 0; // 创建迭代器的方法
};
// 具体聚合类
class ConcreteCollection : public Collection {
private:
std::vector<int> items;
public:
void add(int item) {
items.push_back(item);
}
Iterator* createIterator() override {
return new ConcreteIterator(items);
}
};
// 迭代器接口
class Iterator {
public:
virtual ~Iterator() = default;
virtual bool hasNext() = 0; // 检查是否还有下一个元素
virtual int next() = 0; // 返回下一个元素
};
// 具体迭代器类
class ConcreteIterator : public Iterator {
private:
std::vector<int>::iterator current;
std::vector<int> items;
public:
ConcreteIterator(const std::vector<int>& items) : items(items), current(items.begin()) {}
bool hasNext() override {
return current != items.end();
}
int next() override {
if (hasNext()) {
return *(current++);
}
throw std::out_of_range("No more elements");
}
};
// 客户端代码
int main() {
ConcreteCollection collection;
collection.add(1);
collection.add(2);
collection.add(3);
Iterator* iterator = collection.createIterator();
while (iterator->hasNext()) {
std::cout << iterator->next() << " ";
}
std::cout << std::endl;
delete iterator; // 释放迭代器对象
return 0;
}
中介者模式
中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介对象来封装一组对象之间的交互,从而降低对象间的直接耦合度
核心思想是将复杂的网状通信结构转化为星型结构,使各对象不再显式相互引用,而是通过中介者进行通信。
这种模式特别适用于大型系统中,可以帮助减少组件之间的直接交互,使其更易于维护和扩展。
角色
角色 英文 含义 抽象中介者 Mediator 定义了同事对象之间的通信接口 具体中介者 ConcreteMediator 实现协作对象之间的通信 抽象同事类 Colleague 定义一个接口,用于与中介者通信 具体同事类 ConcreteColleague 实现与中介者通信的方法 客户端 Client 创建具体中介者和同事对象,并设置它们之间的关系 适用场景
场景 描述 系统中对象间存在复杂的引用关系 GUI事件处理、聊天室系统等 对象间通信导致依赖关系混乱 航空管制系统协调飞机、航空公司和机场 需要集中控制对象间交互 MVC框架中的控制器协调模型和视图
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <vector>
class Mediator;
// 抽象同事类
class Colleague {
protected:
std::shared_ptr<Mediator> mediator;
std::string name;
public:
Colleague(std::shared_ptr<Mediator> m, const std::string& n)
: mediator(m), name(n) {}
virtual void send(const std::string& receiver, const std::string& msg) = 0;
virtual void receive(const std::string& msg) = 0;
virtual ~Colleague() = default;
};
// 抽象中介者
class Mediator {
public:
virtual void registerColleague(std::shared_ptr<Colleague> colleague) = 0;
virtual void relay(const std::string& receiver, const std::string& msg) = 0;
virtual ~Mediator() = default;
};
// 具体中介者
class ConcreteMediator : public Mediator {
private:
std::map<std::string, std::shared_ptr<Colleague>> colleagues;
public:
void registerColleague(std::shared_ptr<Colleague> colleague) override {
colleagues[colleague->name] = colleague;
}
void relay(const std::string& receiver, const std::string& msg) override {
if (auto receiverColleague = colleagues.find(receiver); receiverColleague != colleagues.end()) {
receiverColleague->second->receive(msg);
}
}
};
// 具体同事类
class ConcreteColleague : public Colleague {
public:
ConcreteColleague(std::shared_ptr<Mediator> m, const std::string& n)
: Colleague(m, n) {}
void send(const std::string& receiver, const std::string& msg) override {
std::cout << name << " sends to " << receiver << ": " << msg << std::endl;
if (auto m = mediator.lock()) {
m->relay(receiver, msg);
}
}
void receive(const std::string& msg) override {
std::cout << name << " receives: " << msg << std::endl;
}
};
// 客户端代码
int main() {
auto mediator = std::make_shared<ConcreteMediator>();
auto alice = std::make_shared<ConcreteColleague>(mediator, "Alice");
auto bob = std::make_shared<ConcreteColleague>(mediator, "Bob");
mediator->registerColleague(alice);
mediator->registerColleague(bob);
alice->send("Bob", "Hello Bob!");
return 0;
}
备忘录模式
备忘录模式是一种行为型设计模式,它允许在不暴露对象内部状态的情况下保存和恢复对象的先前状态。
角色
角色 英文 含义 发起人 Originator 创建一个备忘录,用以记录当前对象内部状态 备忘录 Memento 存储发起人对象的内部状态,并可以防止发起人以外的其他对象访问备忘录 管理者 Caretaker 负责保存备忘录对象,但不检查备忘录的内容 客户端 Client 创建备忘录对象,并向管理者传递它 适用场景
场景 描述 需要保存和恢复对象的状态 游戏存档、撤销操作 需要封装复杂对象的状态 编辑器中的撤销和重做功能 需要保存对象的状态以便日后恢复 数据库事务回滚、文件备份 需要记录对象的历史状态 版本控制系统 需要实现撤销和重做功能 文本编辑器、绘图软件 需要实现状态的快照功能 配置管理、游戏存档
// 备忘录
class Memento {
private:
std::string state_;
Memento(const std::string& state) : state_(state) {}
friend class Originator; // Originator独享访问权
public:
std::string state() const { return state_; }
};
// 发起人
class Originator {
private:
std::string state_;
public:
void set_state(const std::string& state) { state_ = state; }
std::unique_ptr<Memento> create_memento() {
return std::make_unique<Memento>(state_);
}
void restore_from_memento(const Memento* memento) {
if (!memento) {
throw std::invalid_argument("Memento cannot be null");
}
state_ = memento->state();
}
std::string state() const { return state_; }
};
// 管理者
class Caretaker {
private:
std::vector<std::unique_ptr<Memento>> mementos_;
public:
void add_memento(std::unique_ptr<Memento> m) {
if (!m) {
throw std::invalid_argument("Memento cannot be null");
}
mementos_.push_back(std::move(m));
}
const Memento* get_memento(size_t index) const {
return (index < mementos_.size()) ? mementos_[index].get() : nullptr;
}
};
// 客户端
int main() {
Originator editor;
Caretaker history;
editor.set_state("State1");
history.add_memento(editor.create_memento());
editor.set_state("State2");
history.add_memento(editor.create_memento());
if (auto memento = history.get_memento(0)) {
editor.restore_from_memento(memento);
std::cout << "Current State: " << editor.state() << std::endl;
}
return 0;
}
观察者模式
又称发布-订阅模式,主要用于建立对象之间的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知并被自动更新。
角色
角色 英文 含义 抽象主题 Subject 定义了对象之间依赖的接口,并保持一个列表来管理观察者 具体主题 ConcreteSubject 维护一个观察者列表,并向所有观察者发送通知 抽象观察者 Observer 为所有具体观察者定义一个接口,以支持更新操作 具体观察者 ConcreteObserver 实现抽象观察者的方法,以便在得到更新通知时执行相应操作 客户端 Client 在应用程序中创建具体主题和观察者对象,并建立它们之间的依赖关系 适用场景
- 新闻订阅系统
- 股票行情分析系统
- 聊天室系统
- 用户界面事件处理系统
- 实时数据更新系统
class Observer; // 前向声明 Observer 类,以便在 Subject 类的声明中使用它。
// 抽象主题接口
class Subject {
public:
virtual ~Subject() = default;
virtual void attach(std::shared_ptr<Observer> observer) = 0; // 附加观察者
virtual void detach(std::shared_ptr<Observer> observer) = 0; // 移除观察者
virtual void notify() = 0; // 通知所有观察者
};
// 抽象观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update() = 0; // 更新方法
};
// 具体主题类:按钮
class Button : public Subject {
private:
std::vector<std::shared_ptr<Observer>> observers;
bool isPressed;
public:
Button() : isPressed(false) {}
void attach(std::shared_ptr<Observer> observer) override {
observers.push_back(observer);
}
void detach(std::shared_ptr<Observer> observer) override {
auto it = std::remove(observers.begin(), observers.end(), observer);
if (it != observers.end()) {
observers.erase(it, observers.end());
}
}
void notify() override {
for (const auto& observer : observers) {
observer->update();
}
}
void press() {
isPressed = true;
notify(); // 按钮被按下,通知所有观察者
}
void release() {
isPressed = false;
notify(); // 按钮被释放,通知所有观察者
}
bool isPressed() const {
return isPressed;
}
};
// 具体观察者类:点击事件处理器
class ClickHandler : public Observer {
private:
std::string name;
public:
ClickHandler(const std::string& name) : name(name) {}
void update() override {
std::cout << name << " received button click event." << std::endl;
}
};
// 客户端代码
int main() {
// 创建一个按钮
Button button;
// 创建事件处理程序并注册到按钮上
auto handler1 = std::make_shared<ClickHandler>("Handler 1");
auto handler2 = std::make_shared<ClickHandler>("Handler 2");
auto handler3 = std::make_shared<ClickHandler>("Handler 3");
button.attach(handler1);
button.attach(handler2);
button.attach(handler3);
// 模拟按钮被按下
button.press();
// 模拟按钮被释放
button.release();
// 移除某个事件处理程序
button.detach(handler2);
// 再次模拟按钮被按下
button.press();
return 0;
}
/*
// 输出结果:
Handler 1 received button click event.
Handler 2 received button click event.
Handler 3 received button click event.
Handler 1 received button click event.
Handler 3 received button click event.
Handler 1 received button click event.
Handler 3 received button click event.
*/
状态模式
状态模式是一种行为设计模式,允许对象在其内部状态改变时改变其行为。当一个对象的内在状态改变时,其使用的行为也随之发生变化。
角色
角色 英文 含义 环境 Context 定义客户端使用的接口,并维护一个对策略对象的引用 抽象状态 State 定义一个接口,用以封装与Context的一个特定状态相关的行为 具体状态 ConcreteState 每个子类实现一个与环境接口相关的行为 客户端 Client 创建Context对象并配置其初始状态 适用场景:对象行为高度依赖状态,且状态数量多、转换复杂
典型应用 示例 有限状态机(FSM) 地铁闸机(验票正确开门→通行→关闭) 用户界面交互 按钮的不同状态(正常/禁用/悬停)对应不同响应逻辑 业务流程控制 订单状态(待支付→已支付→发货→完成) 游戏角色行为 角色状态切换(站立→奔跑→攻击)
#include <memory>
#include <iostream>
class Context;
class State {
public:
virtual ~State() = default;
virtual void Handle(Context* context) = 0;
};
class Context {
std::unique_ptr<State> currentState;
public:
void Request() {
if (currentState) {
currentState->Handle(this);
}
}
void setState(std::unique_ptr<State> state) {
if (state) {
currentState = std::move(state);
}
}
};
class ConcreteStateA : public State {
public:
void Handle(Context* context) override;
};
class ConcreteStateB : public State {
public:
void Handle(Context* context) override;
};
void ConcreteStateA::Handle(Context* context) {
if (context) {
// 执行状态A的处理逻辑,然后切换到状态B
context->setState(std::make_unique<ConcreteStateB>());
}
}
void ConcreteStateB::Handle(Context* context) {
if (context) {
// 执行状态B的处理逻辑,然后切换到状态A
context->setState(std::make_unique<ConcreteStateA>());
}
}
int main() {
Context context;
context.setState(std::make_unique<ConcreteStateA>());
context.Request();
context.Request();
return 0;
}
策略模式
策略模式是一种行为设计模式,允许在运行时选择算法的行为。定义一系列的算法封装它们,并使它们可以互换使用。
- 角色
角色 英文 含义 环境 Context 维护对策略对象的引用,并提供一个接口让策略对象访问其数据 策略 Strategy 定义所有支持的算法的公共接口,并使具体策略类实现该接口 具体策略 ConcreteStrategy 封装了具体的算法或行为 客户端 Client 创建环境对象并配置其具体策略
和状态模式的区别,举例说明:我压力大的时候,不想工作,只想打游戏。然后打游戏可以缓解压力。状态:压力大到压力小。但是如何打游戏?自己打,还是和朋友一起打?这就是策略。
#include <iostream>
#include <memory>
// 抽象洗涤策略接口
class WashStrategy {
public:
virtual ~WashStrategy() = default;
virtual void execute() const = 0;
};
// 具体策略:标准洗涤
class StandardWash : public WashStrategy {
public:
void execute() const override {
std::cout << "=== 标准洗涤 ===" << std::endl;
std::cout << "1. 浸泡30分钟" << std::endl;
std::cout << "2. 洗涤45分钟" << std::endl;
std::cout << "3. 漂洗2次" << std::endl;
std::cout << "4. 脱水5分钟" << std::endl;
}
};
// 具体策略:快速洗涤
class QuickWash : public WashStrategy {
public:
void execute() const override {
std::cout << "=== 快速洗涤 ===" << std::endl;
std::cout << "1. 洗涤15分钟" << std::endl;
std::cout << "2. 漂洗1次" << std::endl;
std::cout << "3. 脱水3分钟" << std::endl;
}
};
// 具体策略:强力洗涤
class StrongWash : public WashStrategy {
public:
void execute() const override {
std::cout << "=== 强力洗涤 ===" << std::endl;
std::cout << "1. 浸泡60分钟" << std::endl;
std::cout << "2. 洗涤60分钟" << std::endl;
std::cout << "3. 漂洗3次" << std::endl;
std::cout << "4. 脱水10分钟" << std::endl;
}
};
// 洗衣机(上下文类)
class WashingMachine {
private:
std::unique_ptr<WashStrategy> strategy_;
public:
explicit WashingMachine(std::unique_ptr<WashStrategy> strategy = nullptr)
: strategy_(std::move(strategy)) {}
void setStrategy(std::unique_ptr<WashStrategy> strategy) {
strategy_ = std::move(strategy);
}
void startWashing() const {
if (strategy_) {
strategy_->execute();
} else {
std::cout << "错误:未选择洗涤策略!" << std::endl;
}
}
};
// 使用示例
int main() {
WashingMachine washer;
// 使用标准洗涤
washer.setStrategy(std::make_unique<StandardWash>());
washer.startWashing();
// 切换为快速洗涤
washer.setStrategy(std::make_unique<QuickWash>());
washer.startWashing();
// 切换为强力洗涤
washer.setStrategy(std::make_unique<StrongWash>());
washer.startWashing();
return 0;
}
模板方法模式
模版方法模式是一种行为设计模式,定义一个操作中的算法的骨架,将一些步骤延迟到子类中。模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。
角色
角色 英文 含义 抽象类 AbstractClass 定义一个算法的骨架,实现模板方法,并允许子类通过钩子方法来扩展或重写某些步骤 具体类 ConcreteClass 实现抽象类的模板方法,并重写钩子方法来扩展或修改算法的某些步骤 客户端 Client 创建具体类的对象,并通过模板方法执行算法 钩子方法 HookMethod 在模板方法的某些步骤中提供扩展点,允许子类在不改变算法结构的情况下修改或扩展特定行为 应用场景
场景 描述 多类共享算法框架 文件处理流程(验证→连接→传输→校验)、做饭(...)或饮料冲泡流程(煮沸→冲泡→装杯→调味) 避免重复代码 当多个子类存在共同行为模式且部分步骤需要差异化时 扩展控制权限 通过钩子方法允许子类有条件地改变主流程的执行路径
// 抽象类(模板方法模式)
class AbstractClass {
public:
void TemplateMethod() { // 模板方法(固定流程)
Step1();
Step2();
HookMethod();
}
protected:
virtual void Step1() = 0; // 纯虚函数(子类必须实现)
virtual void Step2() = 0;
virtual void HookMethod() {} // 钩子方法(默认空实现)
};
// 具体类(继承抽象类)
class ConcreteClass : public AbstractClass {
protected:
void Step1() override { /* 具体实现步骤1 */ }
void Step2() override { /* 具体实现步骤2 */ }
void HookMethod() override { /* 覆盖钩子方法 */ }
};
// 客户端
int main() {
ConcreteClass obj;
obj.TemplateMethod(); // 调用模板方法,执行算法的骨架和具体步骤
return 0;
}
访问者模式
访问者模式是一种行为设计模式,允许在不修改对象结构的情况下增加新的操作。访问者使得算法与其所作用的对象分离。 本质:通过双重分派机制实现数据结构与操作的解耦
角色
角色 英文 含义 访问者 Visitor 定义对每个元素(Element)执行操作的接口 具体访问者 ConcreteVisitor 实现访问者的接口,为每种元素类提供具体的操作 元素 Element 定义一个接受访问者的接口 具体元素 ConcreteElement 实现元素的接口,并存储状态信息或数据 对象结构 ObjectStructure 维护元素对象的集合,并提供一个接口让访问者遍历这些元素 客户端 Client 创建访问者和元素对象,并通过对象结构将它们连接起来 应用场景
场景 描述 对象结构复杂且经常变化 当对象的内部结构很复杂,并且经常需要增加新的操作时 需要对一个对象结构中的对象进行多种不同且不相关的操作 当需要对一组对象执行多个操作,而这些操作彼此之间没有关联时 封装算法 当需要将算法与对象结构分离时,可以使用访问者模式 增加新的操作 当需要向现有对象结构中添加新功能时,可以使用访问者模式而不需要修改现有的元素类 简化对象结构 当对象的内部状态很多,并且这些状态经常变化时,可以使用访问者模式来简化对象结构的维护 数据结构与操作分离 当需要将算法与其所作用的对象分离时,可以使用访问者模式
#include <iostream>
#include <vector>
// 前向声明
class ConcreteElementA;
class ConcreteElementB;
// 访问者接口
class Visitor {
public:
virtual void visit(ConcreteElementA* element) = 0;
virtual void visit(ConcreteElementB* element) = 0;
};
// 元素接口
class Element {
public:
virtual void accept(Visitor& visitor) = 0;
virtual ~Element() = default;
};
// 具体元素A
class ConcreteElementA : public Element {
public:
explicit ConcreteElementA(int data) : data_(data) {}
void accept(Visitor& visitor) override {
visitor.visit(this); // 双重分派
}
int getData() const { return data_; }
private:
int data_;
};
// 具体元素B
class ConcreteElementB : public Element {
public:
explicit ConcreteElementB(const std::string& name) : name_(name) {}
void accept(Visitor& visitor) override {
visitor.visit(this); // 双重分派
}
std::string getName() const { return name_; }
private:
std::string name_;
};
// 具体访问者:数据导出
class DataExporter : public Visitor {
public:
void visit(ConcreteElementA* element) override {
std::cout << "[Exporter] ElementA data: " << element->getData() << "\n";
}
void visit(ConcreteElementB* element) override {
std::cout << "[Exporter] ElementB name: " << element->getName() << "\n";
}
};
// 具体访问者:数据统计
class DataAnalyzer : public Visitor {
public:
void visit(ConcreteElementA* element) override {
total_ += element->getData();
std::cout << "[Analyzer] Current total: " << total_ << "\n";
}
void visit(ConcreteElementB* element) override {
names_ += element->getName() + " ";
std::cout << "[Analyzer] Collected names: " << names_ << "\n";
}
private:
int total_ = 0;
std::string names_;
};
// 对象结构
class ObjectStructure {
public:
void add(Element* element) {
elements_.push_back(element);
}
void apply(Visitor& visitor) {
for (auto* elem : elements_) {
elem->accept(visitor);
}
}
~ObjectStructure() {
for (auto* elem : elements_) {
delete elem;
}
}
private:
std::vector<Element*> elements_;
};
int main() {
ObjectStructure structure;
structure.add(new ConcreteElementA(42));
structure.add(new ConcreteElementB("Test"));
structure.add(new ConcreteElementA(100));
DataExporter exporter;
structure.apply(exporter);
DataAnalyzer analyzer;
structure.apply(analyzer);
return 0;
}
空对象模式
空对象模式是一种行为模式,用于避免在程序中创建空对象。它通常用在客户端代码中,以简化对可能不存在的对象的处理逻辑。 本质:用一个空对象代替NULL,避免在程序中直接使用NULL值
角色
角色 英文 含义 抽象对象 AbstractObject 定义对象的接口 具体对象 ConcreteObject 实现抽象对象的接口 空对象 NullObject 实现抽象对象的接口,但不包含任何实际数据或行为 客户端 Client 使用抽象对象接口与具体对象或空对象进行交互 应用场景
场景 描述 避免NULL引用 当对象可能为空时,使用空对象模式可以简化对NULL引用的检查 简化客户端代码 当客户端需要对可能不存在的对象进行操作时,使用空对象模式可以减少条件判断和NULL检查的复杂性 统一接口 当需要为不同类型的对象提供统一的接口时,可以使用空对象模式来处理那些不存在的对象
// 抽象对象接口定义
class AbstractObject {
public:
virtual void operation() = 0;
virtual ~AbstractObject() = default;
};
// 具体对象实现
class ConcreteObject : public AbstractObject {
public:
void operation() override {
std::cout << "Performing operation on concrete object." << std::endl;
}
};
// 空对象实现
class NullObject : public AbstractObject {
public:
void operation() override {
std::cout << "Performing operation on null object (no-op)." << std::endl;
}
};
// 客户端代码
void processObject(AbstractObject* obj) {
if (obj) {
obj->operation();
} else {
std::cout << "Object is null." << std::endl;
}
}
int main() {
ConcreteObject* concreteObj = new ConcreteObject();
NullObject* nullObj = new NullObject();
AbstractObject* nullPtr = nullptr;
processObject(concreteObj); // 输出:Performing operation on concrete object.
processObject(nullObj); // 输出:Performing operation on null object (no-op).
processObject(nullPtr); // 输出:Object is null.
delete concreteObj;
delete nullObj;
return 0;
}