1. 创建型模式
1.1. 单例模式
概念:确保某个类只有一个实例,并提供全局访问点来获取这个实例。适用于需要全局共享的资源,如数据库连接池、日志管理器等
特点:
- 唯一性:类的实例唯一存在
- 全局访问点:通过静态方法访问该实例
- 延迟初始化:仅在第一次使用时创建,节省资源(懒汉)
适用场景:
- 配置管理器:读取和管理全局配置(数据库连接信息、文件路径等)
- 日志记录器:记录日志,确保所有模块共享同一日志实例
- 线程池:全局统一管理线程的分配和回收
- 硬件访问:打印机驱动管理器、确保访问同一个硬件实例
1.1.1. 实现
- 通过静态变量和手动加锁实现(线程不安全,需要额外的同步操作)
class Singleton{
private:
static std::mutex mutex;
static Singleton *instance;
Singleton(/* args */) {}
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
public:
static Singleton *getInstance(){
if (instance == nullptr){
std::lock_guard<std::mutex> lock(mutex); // 超出作用域自动解锁
if (instance == nullptr){
instance = new Singleton();
}
}
return instance;
}
};
Singleton *Singleton::instance = nullptr;
std::mutex Singleton::mutex;
2. 工厂方法模式
概念:定义一个工厂接口,由子类来决定实例化哪一个类。这样可以将对象的创建逻辑与使用逻辑分离,客户端只需要通过工厂接口获取对象,而不需要直接依赖具体的类。常用于将对象的创建与使用分离的场景
结构:
- 抽象产品(Product):抽象类,不能直接实例化
- 定义对象的公共接口
- 包含纯虚函数,要求子类必须实现
- 使用虚析构函数,确保子类正确析构
- 具体产品(Concrete Product):
- 继承抽象产品类,实现抽象产品接口,定义具体对象的行为
- 抽象工厂(Creator/Factory):抽象类
- 定义工厂方法接口,用于创建对象
- 具体工厂(Concrete Factory):
- 实现工厂方法,负责创建具体产品对象
- 客户端(Client):
- 通过工厂接口创建对象,而不依赖具体的类
实现例子:
// 抽象产品
class Product {
public:
virtual void use() = 0;
};
// 具体产品A
class ConcreteProductA : public Product { /*...*/ };//use的具体实现
// 抽象工厂( Creator )
class Creator {
public:
virtual Product* createProduct() = 0; // 工厂方法
};
// 具体工厂A
class ConcreteCreatorA : public Creator {
public:
Product* createProduct() override {
return new ConcreteProductA(); // 创建具体产品A
}
};
// 客户端代码
Creator* creator = new ConcreteCreatorA();
Product* product = creator->createProduct(); // 创建ProductA
product->use();
1.3. 抽象工厂模式
概念:为一组相关或相互依赖的对象提供一个创建接口,而无需指定它们具体的类
核心要素:
- 抽象工厂:定义创建一系列对象的接口
- 具体工厂:实现创建特定风格对象的工厂
- 抽象产品:定义产品的公共接口
- 具体产品:特定风格的产品实现
- 客户端:通过抽象工厂创建产品,而不关心具体产品的实现
1.3.1. 工厂、抽象工厂的区别
- 关键区别
- 应用场景
1.4. 建造者模式
概念:
- 将复杂对象的建造步骤分成多步,让我们可以灵活的控制这些步骤
- 通过不同的建造者,构建过程可以生成不同的产品
特点:
- 由多个部分组成的复杂对象
- 构建步骤固定,但是各部分内容可以变化
- 需要创建不同类型的对象
结构:
- 产品:最终构造的复杂对象,由多个部分构成
- 建造者:定义对象的构建步骤
- 具体建造者:实现具体的构建逻辑,构建特定类型的产品
- 指挥者:控制建造过程,调用建造者的步骤按顺序完成构建
- 客户端:选择具体的建造者,通过指挥者完成产品构建,并获得最终产品
1.5. 原型模式
概念:通过复制一个现有的对象,快速生成一个新的对象,而不需要再次通过类的实例化来创建。
代码实现:
// 抽象原型类
class Prototype {
public:
virtual ~Prototype() = default;
virtual Prototype* clone() const = 0; // 多态克隆接口
};
// 具体原型类
class ConcretePrototype : public Prototype {
public:
int* data;
Prototype* clone() const override {
ConcretePrototype* copy = new ConcretePrototype();
copy->data = new int(*this->data); // 深拷贝在clone()中统一处理
return copy;
}
};
// 使用
Prototype* original = new ConcretePrototype();
Prototype* copy = original->clone(); // 动态克隆,无需知道具体类型
原型模式和拷贝构造函数的区别:
2. 结构型模式
结构型模式关注类和对象之间的组合和关系,旨在通过简化系统结构,提高代码的可扩展性和灵活性
2.1. 适配器模式
概念:可以将一个类的接口转换成客户端期望的接口,使得原本不能一起工作的类能够协同工作,用于解决接口不兼容的问题。
应用场景:
- 接口转换:
- 集成遗留代码
- 接口统一:希望通过统一的接口来调用多种功能不同但相似的类
核心组成:
- 目标接口:定义客户端期望的接口标准
- 适配者:现有的类,提供了功能但接口与目标接口不兼容
- 适配器:连接目标接口和适配者,负责接口的转换
2.2. 桥接模式
2.3. 组合模式
2.4. 装饰器模式
2.5. 外观模式
2.6. 代理模式
3. 行为型模式
3.1. 责任链模式
3.2. 命令模式
3.3. 状态模式
3.4. 策略模式
3.5. 模板方法模式
3.6. 迭代器模式
3.7. 观察者模式
特点:
- 松耦合:主题与观察者之间通过接口交互,彼此不直接依赖,可以独立扩展
- 动态订阅与取消订阅:观察者可以随时订阅或取消订阅,运行灵活
- 通知机制自动化:主题变化后,会统一通知所有订阅者
适用场景:
- 消息通知:用户订阅后,新闻更新自动推送
- 数据驱动更新:界面设计中,数据变化时需要动态更新UI
- 事件触发系统:游戏中玩家状态变化需要通知其他玩家,或者股票推送实时行情
- 抽象观察者接口:定义一个虚函数,所有观察者类都必须实现这个方法,用于接收通知
- 主题类:保存一个