设计模式帮助开发者用更优雅、可复用的方式解决常见问题,提高代码的可读性、可维护性和可扩展性。熟练掌握这些模式,是面向对象设计进阶的重要一步。
设计模式分类
创建型、结构性、行为型
创建型:单例、工厂方法、抽象工厂、建造者...
结构性:适配器、桥接、组合、装饰、外观...
行为型:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式
单例设计模式
一个类,全局永远只有一个实例,并且提供一个全局访问点。
使用场景
配置类、日志工具类、数据库连接、线程池、缓存对象
核心特点
构造方法私有(禁止外部 new)
提供静态方法获取唯一实例
全局唯一,不重复创建
设计过程
1.私有化构造函数
2.删除拷贝构造与赋值重载
3.公开静态成员函数
4.当前类对象 定义在私有或者 静态成员函数内定义静态的类对象
饿汉式
程序启动就创建好实例,天生线程安全。
优点:线程安全、简单
缺点:不用也会创建,浪费一点资源
懒汉式
最经典,但线程不安全。第一次使用才创建。
多线程下会创建多个实例,不安全
双重检查锁(DCL)线程安全
线程安全 + 懒加载。
优点:线程安全、懒加载、性能高
为什么要两次检查?
-
第一次检查(不加锁)
- 实例已经创建 → 直接返回,不用加锁,速度极快
- 实例未创建 → 才进入加锁逻辑
-
加锁
- 保证同一时间只有一个线程能创建实例
-
第二次检查(加锁后)
- 防止多个线程同时卡在第一次检查
- 确保只创建一次实例
面试题
为什么单例要私有构造?
防止外部 new 破坏单例。
饿汉式 vs 懒汉式区别?
饿汉:类加载就创建,线程安全;
懒汉:用到才创建,节省资源。
双重检查为什么要加 volatile?
防止 new Singleton() 指令重排,导致空指针。
如何防止反射破坏单例?
用枚举单例最安全。
工厂模式
简单工厂、工厂方法、抽象工厂
简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它通过一个工厂类来负责创建所有产品对象,客户端只需要告:诉工厂需要什么产品,工厂就会返回相应的产品实例。
简单工厂
依据用户需求,创建特定的产品
创建过程
1.设计产品的基类
2.设计具体的产品
3.设计简单工厂类
4.根据需求创建产品
核心特点
1.只有一个工厂类
2.根据传入的参数决定创建哪种产品
3.将对象的创建和使用分离
cpp
#include <memory>
class Phone {//接口类
public:
virtual void tell(string phone) = 0;
};
class MiPhone :public Phone {
public:
void tell(string phone)override {
cout << "MiPhone tell:" << phone << endl;
}
};
class HuaWeiPhone :public Phone {
public:
void tell(string phone)override {
cout << "HuaWeiPlone tell:" << phone << endl;
}
};
class VivoPhone :public Phone {
public:
void tell(string phone)override {
cout << "VivoPlone tell:" << phone << endl;
}
};
class PhoneFactory {
public:
enum Type{Mi,HuaWei,Vivo};
static unique_ptr<Phone> create(Type type) {
switch (type) {
case Mi:return unique_ptr<Phone>(new MiPhone());
case HuaWei:return unique_ptr<Phone>(new HuaWeiPhone());
case Vivo:return unique_ptr<Phone>(new VivoPhone());
}
return nullptr;
}
};
int main() {
unique_ptr<Phone>phone = PhoneFactory::create(PhoneFactory::Vivo);
phone->tell("110");
unique_ptr<Phone>phone2 = PhoneFactory::create(PhoneFactory::HuaWei);
phone->tell("120");
return 0;
}
工厂方法
工厂方法模式 (Factory Method Pattern)是一种创建型设计模式,它定义了用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法将对象的实例化延迟到子类中完成。
解决简单工厂创建产品的局限性
设计核心思想
将工厂创建产品抽象为一个接口,具体创建某一种产品由工厂的派生类来完成。
创建过程
1.定义工厂的接口类
2.定义生产具体产品的工厂派生类
cpp
//工厂方法
class PhoneFactory {
public:
//工厂的创建产品的函数(方法)
virtual shared_ptr<Phone>create() = 0;
};
class HuaWeiFactory :public PhoneFactory {
public:
shared_ptr<Phone>create()override {
return shared_ptr<Phone>(new HuaWeiPhone());
}
};
class MiFactory :public PhoneFactory {
public:
shared_ptr<Phone>create()override {
return shared_ptr<Phone>(new MiPhone());
}
};
class VivoFactory :public PhoneFactory {
public:
shared_ptr<Phone>create()override {
return shared_ptr<Phone>(new VivoPhone());
}
};
int main() {
shared_ptr<Phone>hwPhone = HuaWeiFactory().create();
hwPhone->tell("119");
return 0;
}
核心特点
1.每个具体的产品对应一个具体的工厂
2.解决了简单工厂违反开闭原则的问题
3.符合"单一职责"和"开闭原则"
开闭原则:添加新产品只需添加新工厂类,无需修改现有代码。
单一职责:每个工厂只负责创建一种产品
抽象工厂
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
基于工厂方法设计的,在工厂基类中,提供对产品的一些操作。
简单理解:抽象工厂将创建和使用组合到一起。
核心特点
1.创建产品族
2.一个工厂可以创建多种产品
3.强调产品之间的约束和关系
观察者模式
观察者模式是一种行为型设计模式,用于定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动收到通知并更新。
一个主题(subject)被多个观察者(observer)监听(依赖),当主题的数据(成员变量)发生变量时,通知所有的观察者。
核心角色
Subject(被观察者/主题):管理观察者列表,状态变了通知所有人
Observer(观察者):有一个更新接口,被主题调用
ConcreteSubject:具体主题,存状态,状态变了触发通知
ConcreteObserver:具体观察者,收到通知做自己的事
Subject
维护观察者列表,提供 attach / detach / notify
Observer
定义 update 接口
ConcreteSubject
就是 Subject 结构体 + state + set_state
ConcreteObserver
就是 ConcreteObserver + 自己的 update 实现