一、单例模式(Singleton Pattern)
1. 设计本质与动机
单例的核心诉求是全局唯一 + 统一访问入口,本质是用类的封装性替代全局变量,同时对实例化时机、生命周期、创建逻辑进行可控管理。它要解决的核心问题是:避免一个全局资源被重复创建、多实例状态不一致,同时屏蔽对象创建细节。
2. 核心角色与结构
- 单例类:私有化构造 / 拷贝 / 赋值,内部持有唯一实例,对外提供静态获取接口。
- 无其他外部角色,调用方直接通过类名访问。
3. 主流实现方案与 C++ 细节
方案 1:饿汉式(程序启动即创建)
实例在程序进入 main 函数前就完成初始化,天生线程安全。
cpp
class HungrySingleton {
private:
HungrySingleton() = default;
HungrySingleton(const HungrySingleton&) = delete;
HungrySingleton& operator=(const HungrySingleton&) = delete;
~HungrySingleton() = default;
static HungrySingleton instance; // 静态成员,程序启动即构造
public:
static HungrySingleton& getInstance() {
return instance;
}
};
// 类外初始化
HungrySingleton HungrySingleton::instance;
- 优点:无锁、线程安全、实现简单。
- 缺点:启动即占用资源;若单例依赖外部初始化参数则无法使用;存在 "静态初始化顺序问题"(不同编译单元的静态变量初始化顺序不确定)。
方案 2:懒汉式
第一次使用时才创建,通过双重检查减少锁的开销
cpp
#include <mutex>
#include <memory>
class LazySingleton {
private:
LazySingleton() = default;
LazySingleton(const LazySingleton&) = delete;
LazySingleton& operator=(const LazySingleton&) = delete;
static std::unique_ptr<LazySingleton> instance;
static std::mutex mtx;
public:
static LazySingleton* getInstance() {
if (instance == nullptr) { // 第一次检查:无锁快速判断
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) { // 第二次检查:加锁后确认
instance.reset(new LazySingleton());
}
}
return instance.get();
}
};
2. 简单工厂模式(Simple Factory)
核心定义
由一个工厂类根据传入的参数,动态决定创建哪一种产品的实例。又称静态工厂模式,不属于 GoF 23 种设计模式,是工厂模式的基础形态。
适用场景
- 产品种类较少、创建逻辑简单
- 调用方不关心对象创建细节,只需要获取对象
- 需求稳定,不会频繁新增产品类型
C++ 代码实现
以图形创建为例:
cpp
#include <iostream>
#include <string>
// 抽象产品
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() = default;
};
// 具体产品:圆形
class Circle : public Shape {
public:
void draw() override { std::cout << "绘制圆形" << std::endl; }
};
// 具体产品:矩形
class Rectangle : public Shape {
public:
void draw() override { std::cout << "绘制矩形" << std::endl; }
};
// 工厂类:统一创建所有产品
class ShapeFactory {
public:
static Shape* createShape(const std::string& type) {
if (type == "circle") return new Circle();
else if (type == "rect") return new Rectangle();
return nullptr;
}
};
// 使用方式
int main() {
Shape* s1 = ShapeFactory::createShape("circle");
s1->draw();
Shape* s2 = ShapeFactory::createShape("rect");
s2->draw();
delete s1; delete s2;
return 0;
}
优缺点
- 优点:实现极简,对象创建与使用分离,调用方无需感知具体产品类。
- 缺点:违反开闭原则,新增产品必须修改工厂类代码;产品多时工厂类职责臃肿。
3. 工厂方法模式(Factory Method)
核心定义
定义一个创建产品的抽象工厂接口,让具体工厂子类决定实例化哪一个具体产品。将产品的创建延迟到工厂子类中完成,是 GoF 标准创建型模式。
核心区别(对比简单工厂)
每个具体产品对应一个专属的具体工厂,新增产品时只需新增产品类 + 工厂类,无需修改原有代码。
适用场景
- 系统无法预知需要创建的对象的具体类型
- 希望由子类决定创建哪个具体对象
- 需要灵活扩展产品种类,且不影响原有代码
C++ 代码实现
cpp
#include <iostream>
// 抽象产品
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() = default;
};
// 具体产品
class Circle : public Shape {
public:
void draw() override { std::cout << "绘制圆形" << std::endl; }
};
class Rectangle : public Shape {
public:
void draw() override { std::cout << "绘制矩形" << std::endl; }
};
// 抽象工厂
class ShapeFactory {
public:
virtual Shape* createShape() = 0;
virtual ~ShapeFactory() = default;
};
// 具体工厂:每个产品对应一个工厂
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* factory = new CircleFactory();
Shape* shape = factory->createShape();
shape->draw();
delete factory; delete shape;
return 0;
}
优缺点
- 优点:完全符合开闭原则,新增产品只需新增对应工厂类;高层模块只依赖抽象,解耦彻底。
- 缺点:类数量成对增长,产品多时会出现类爆炸,提升系统复杂度。
4. 抽象工厂模式(Abstract Factory)
核心定义
提供一个创建一系列相关 / 相互依赖对象的接口,无需指定它们的具体类。是 GoF 标准创建型模式,针对「产品族」而非单个产品。
核心概念
- 产品等级:同一种产品的不同实现(如按钮分 Windows 按钮、Mac 按钮)
- 产品族:同一个工厂生产的、配套使用的一组产品(如 Windows 工厂生产 Windows 按钮 + Windows 文本框)
工厂方法面向单个产品等级 ,抽象工厂面向多个产品等级(产品族)。
适用场景
- 系统需要多套产品族,且同产品族的产品必须配套使用
- 需要一键切换整套产品(如一键切换 UI 主题)
- 产品等级结构稳定,不会频繁新增产品类型
C++ 代码实现
以跨平台 UI 组件为例(按钮 + 文本框两个产品等级,Windows+Mac 两个产品族):
cpp
#include <iostream>
// 抽象产品A:按钮
class Button {
public:
virtual void click() = 0;
virtual ~Button() = default;
};
// 具体产品A
class WindowsButton : public Button {
public:
void click() override { std::cout << "Windows按钮点击" << std::endl; }
};
class MacButton : public Button {
public:
void click() override { std::cout << "Mac按钮点击" << std::endl; }
};
// 抽象产品B:文本框
class TextBox {
public:
virtual void input() = 0;
virtual ~TextBox() = default;
};
// 具体产品B
class WindowsTextBox : public TextBox {
public:
void input() override { std::cout << "Windows文本框输入" << std::endl; }
};
class MacTextBox : public TextBox {
public:
void input() override { std::cout << "Mac文本框输入" << std::endl; }
};
// 抽象工厂:定义创建所有产品等级的接口
class UIFactory {
public:
virtual Button* createButton() = 0;
virtual TextBox* createTextBox() = 0;
virtual ~UIFactory() = default;
};
// 具体工厂:Windows产品族工厂
class WindowsUIFactory : public UIFactory {
public:
Button* createButton() override { return new WindowsButton(); }
TextBox* createTextBox() override { return new WindowsTextBox(); }
};
// 具体工厂:Mac产品族工厂
class MacUIFactory : public UIFactory {
public:
Button* createButton() override { return new MacButton(); }
TextBox* createTextBox() override { return new MacTextBox(); }
};
// 使用方式:更换工厂即可切换整套UI风格
int main() {
UIFactory* factory = new WindowsUIFactory();
Button* btn = factory->createButton();
TextBox* box = factory->createTextBox();
btn->click();
box->input();
delete factory; delete btn; delete box;
return 0;
}
优缺点
- 优点:隔离具体类生成,客户端无需感知产品细节;产品族切换成本极低;保证同产品族产品配套使用。
- 缺点:开闭原则倾斜------ 新增产品族容易(加新工厂),新增产品等级极难(需要修改所有工厂类)。
5. 观察者模式(Observer Pattern)
核心定义
定义对象间一对多的依赖关系:当一个对象(主题 / 被观察者)的状态发生改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。又称发布 - 订阅模式,是 GoF 标准行为型模式。
核心思想
主题维护一个观察者列表,提供注册、移除、通知三个接口;观察者实现统一的更新接口。状态变化时,主题遍历列表,逐个通知所有观察者。
适用场景
- 一个对象的状态变化需要联动通知多个其他对象
- 对象间需要松耦合的联动,被观察者无需知道观察者的业务细节
- 事件订阅、消息推送、UI 数据绑定、MVC 架构等场景
C++ 代码实现
以公众号订阅为例:
cpp
#include <iostream>
#include <vector>
#include <string>
// 抽象观察者
class Observer {
public:
virtual void update(const std::string& msg) = 0;
virtual ~Observer() = default;
};
// 抽象主题(被观察者)
class Subject {
public:
virtual void attach(Observer* obs) = 0; // 订阅
virtual void detach(Observer* obs) = 0; // 取消订阅
virtual void notify() = 0; // 广播通知
virtual ~Subject() = default;
};
// 具体主题:公众号
class OfficialAccount : public Subject {
private:
std::vector<Observer*> observers;
std::string article;
public:
void attach(Observer* obs) override { observers.push_back(obs); }
void detach(Observer* obs) override {
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == obs) { observers.erase(it); break; }
}
}
void notify() override {
for (auto obs : observers) obs->update(article);
}
void publish(const std::string& title) {
article = title;
std::cout << "公众号发布:" << title << std::endl;
notify();
}
};
// 具体观察者:用户
class User : public Observer {
private:
std::string name;
public:
User(std::string n) : name(std::move(n)) {}
void update(const std::string& msg) override {
std::cout << "用户【" << name << "】收到推送:" << msg << std::endl;
}
};
// 使用方式
int main() {
OfficialAccount account;
User u1("张三"), u2("李四");
account.attach(&u1);
account.attach(&u2);
account.publish("C++设计模式入门");
account.detach(&u1);
account.publish("观察者模式实战");
return 0;
}
优缺点
- 优点:主题与观察者松耦合,可独立扩展;支持广播通信,一次触发全员通知。
- 缺点:观察者数量多时通知效率低;循环依赖会触发死循环;主题只通知状态变化,不传递变化细节。