设计模式实战对比
用"前后对比"的方式,让你真切感受每个设计模式的价值
面试热度标记:⭐⭐⭐⭐⭐ 必考 | ⭐⭐⭐⭐ 常考 | ⭐⭐⭐ 偶尔考 | ⭐⭐ 很少考
目录
一、创建型模式
1. 单例模式 ⭐⭐⭐⭐⭐
面试必考!手写单例是基本要求
一句话记住:全局只要一个
❌ 不用设计模式
// 配置管理器
class Config {
public:
string dbHost;
string dbPort;
Config() {
// 每次都要读文件
ifstream file("config.ini");
file >> dbHost >> dbPort;
cout << "读取配置文件..." << endl;
}
};
// 到处创建实例
class OrderService {
Config* config = new Config(); // 读一次文件
};
class UserService {
Config* config = new Config(); // 又读一次文件
};
class ProductService {
Config* config = new Config(); // 再读一次文件
};
// 问题:
// 1. 配置被读了N次,浪费资源
// 2. 不同实例的配置可能不一致
// 3. 内存里有N份相同的配置,浪费空间
✅ 用单例模式
class Config {
private:
static Config* instance;
Config() {
// 只读一次文件
ifstream file("config.ini");
file >> dbHost >> dbPort;
cout << "读取配置文件..." << endl;
}
public:
static Config* getInstance() {
if (!instance) instance = new Config();
return instance;
}
};
// 使用
Config* config = Config::getInstance(); // 全局唯一
// 不管在哪里调用,都是同一个实例
// 配置只读一次,内存只有一份
价值:全局唯一、节省资源、数据一致
2. 工厂模式 ⭐⭐⭐⭐⭐
面试必考!常问简单工厂、工厂方法、抽象工厂的区别
一句话记住:创建逻辑集中管
❌ 不用设计模式
// 业务代码里到处new对象
class OrderService {
Database* db = new MySQL(); // 硬编码
};
class UserService {
Database* db = new MySQL(); // 重复代码
};
class ProductService {
Database* db = new MySQL(); // 改数据库要改3个地方!
};
// 问题:
// 1. 想换成PostgreSQL?要改N个地方
// 2. 创建逻辑分散,难以统一管理
// 3. 违反了依赖倒置原则
✅ 用工厂模式
class DatabaseFactory {
public:
static Database* create(string type) {
if (type == "mysql") return new MySQL();
if (type == "postgresql") return new PostgreSQL();
return nullptr;
}
};
// 业务代码
class OrderService {
Database* db = DatabaseFactory::create("mysql");
};
// 想换数据库?只改一个地方!
// 或者从配置文件读取
Database* db = DatabaseFactory::create(config.getDBType());
价值:创建逻辑集中、切换实现只需改一处、符合依赖倒置
3. 建造者模式 ⭐⭐⭐⭐
常考!链式调用的典型应用
一句话记住:复杂对象一步步建
❌ 不用设计模式
// 订单对象,属性很多
class Order {
public:
string orderId;
string userId;
string productId;
int quantity;
double price;
string address;
string phone;
string remark;
// ... 还有20个属性
};
// 创建订单:构造函数参数爆炸!
Order order("001", "user001", "prod001", 2, 99.9,
"北京市朝阳区...", "13800138000", "尽快发货",
...); // 参数太多,容易搞错
// 或者:分步设置,但可能漏掉必填项
Order order;
order.orderId = "001";
order.userId = "user001";
// 忘了设置productId!编译不报错,运行时出问题
✅ 用建造者模式
class OrderBuilder {
private:
Order* order;
public:
OrderBuilder() : order(new Order()) {}
// 必填项:链式调用
OrderBuilder& setOrderId(string id) {
order->orderId = id;
return *this;
}
OrderBuilder& setUserId(string id) {
order->userId = id;
return *this;
}
OrderBuilder& setProductId(string id) {
order->productId = id;
return *this;
}
// 可选项
OrderBuilder& setAddress(string addr) {
order->address = addr;
return *this;
}
OrderBuilder& setRemark(string rmk) {
order->remark = rmk;
return *this;
}
Order* build() {
// 校验必填项
if (order->orderId.empty() || order->userId.empty()) {
throw "必填项不能为空";
}
return order;
}
};
// 使用:清晰、不易出错
Order* order = OrderBuilder()
.setOrderId("001")
.setUserId("user001")
.setProductId("prod001")
.setAddress("北京市朝阳区...")
.setRemark("尽快发货")
.build();
价值:参数清晰、链式调用、可以校验必填项
4. 原型模式 ⭐⭐⭐
偶尔考!常与深拷贝、浅拷贝一起问
一句话记住:复制比创建快
❌ 不用设计模式
// 邮件模板
class EmailTemplate {
public:
string subject;
string content;
string sender;
string signature;
vector<string> attachments;
EmailTemplate(string s, string c, string snd, string sig)
: subject(s), content(c), sender(snd), signature(sig) {
// 复杂的初始化逻辑
// 可能需要查询数据库、读取文件等
}
};
// 每次发邮件都要重新创建
EmailTemplate* email1 = new EmailTemplate("通知", "内容...", "admin", "系统");
EmailTemplate* email2 = new EmailTemplate("通知", "内容...", "admin", "系统");
EmailTemplate* email3 = new EmailTemplate("通知", "内容...", "admin", "系统");
// 重复创建,浪费资源
✅ 用原型模式
class EmailTemplate {
public:
// ... 属性同上
// 克隆方法
EmailTemplate* clone() {
EmailTemplate* copy = new EmailTemplate();
copy->subject = this->subject;
copy->content = this->content;
copy->sender = this->sender;
copy->signature = this->signature;
copy->attachments = this->attachments; // 深拷贝
return copy;
}
};
// 使用:先创建一个原型,然后克隆
EmailTemplate* prototype = new EmailTemplate("通知", "内容...", "admin", "系统");
EmailTemplate* email1 = prototype->clone();
EmailTemplate* email2 = prototype->clone();
EmailTemplate* email3 = prototype->clone();
// 克隆比重新创建快得多!
价值:避免重复初始化、性能更好、适合创建成本高的对象
二、结构型模式
5. 适配器模式 ⭐⭐⭐⭐⭐
面试必考!常问与装饰器模式的区别
一句话记住:老代码包一层
❌ 不用设计模式
// 旧系统:XML格式的用户数据
class OldUserService {
public:
string getUserXML(int id) {
return "<user><id>" + to_string(id) + "</id><name>张三</name></user>";
}
};
// 新系统:要求JSON格式
// 方案1:直接改OldUserService(改老代码,风险大!)
class OldUserService {
public:
string getUserJSON(int id) { // 新增方法
return "{\"id\":" + to_string(id) + ",\"name\":\"张三\"}";
}
string getUserXML(int id) { ... } // 旧方法还在
};
// 问题:
// 1. 改了老代码,可能影响其他使用XML的地方
// 2. 老代码和新代码混在一起,难以维护
// 3. 违反了开闭原则
✅ 用适配器模式
// 新系统接口
class UserService {
public:
virtual string getUserJSON(int id) = 0;
};
// 适配器:不改老代码,包一层
class UserServiceAdapter : public UserService {
private:
OldUserService* oldService;
public:
string getUserJSON(int id) override {
string xml = oldService->getUserXML(id);
// XML转JSON
return convertXMLToJSON(xml);
}
};
// 使用
UserService* service = new UserServiceAdapter();
string json = service->getUserJSON(1); // 对外是JSON,内部调用XML
价值:不改老代码、新旧系统兼容、职责分离
6. 装饰器模式 ⭐⭐⭐⭐⭐
面试必考!常问与继承的区别、与适配器的区别
一句话记住:层层包装加功能
❌ 不用设计模式
// 咖啡店问题
class Coffee {
public:
virtual double cost() = 0;
};
class SimpleCoffee : public Coffee {
double cost() override { return 10; }
};
// 加牛奶
class CoffeeWithMilk : public Coffee {
double cost() override { return 13; }
};
// 加糖
class CoffeeWithSugar : public Coffee {
double cost() override { return 11; }
};
// 加牛奶和糖
class CoffeeWithMilkAndSugar : public Coffee {
double cost() override { return 14; }
};
// 加牛奶、糖、奶油
class CoffeeWithMilkAndSugarAndCream : public Coffee {
double cost() override { return 19; }
};
// 问题:
// 组合爆炸!N种配料 = 2^N 种子类
// 加一种新配料,要新建一堆子类
✅ 用装饰器模式
// 咖啡基类
class Coffee {
public:
virtual double cost() = 0;
virtual string desc() = 0;
};
class SimpleCoffee : public Coffee {
double cost() override { return 10; }
string desc() override { return "咖啡"; }
};
// 装饰器基类
class CoffeeDecorator : public Coffee {
protected:
Coffee* coffee;
public:
CoffeeDecorator(Coffee* c) : coffee(c) {}
};
// 牛奶装饰器
class Milk : public CoffeeDecorator {
public:
Milk(Coffee* c) : CoffeeDecorator(c) {}
double cost() override { return coffee->cost() + 3; }
string desc() override { return coffee->desc() + "+牛奶"; }
};
// 糖装饰器
class Sugar : public CoffeeDecorator {
public:
Sugar(Coffee* c) : CoffeeDecorator(c) {}
double cost() override { return coffee->cost() + 1; }
string desc() override { return coffee->desc() + "+糖"; }
};
// 使用:任意组合!
Coffee* coffee = new SimpleCoffee(); // 10元
coffee = new Milk(coffee); // 13元
coffee = new Sugar(coffee); // 14元
coffee = new Milk(coffee); // 17元(双份牛奶)
cout << coffee->desc() << " = " << coffee->cost() << "元" << endl;
// 输出:咖啡+牛奶+糖+牛奶 = 17元
价值:自由组合、避免继承爆炸、灵活扩展
7. 代理模式 ⭐⭐⭐⭐⭐
面试必考!常问动态代理、静态代理、与适配器的区别
一句话记住:找个中间人办事
❌ 不用设计模式
// 图片加载
class Image {
public:
Image(string filename) {
// 构造时就加载图片,可能很慢
loadFromDisk(filename);
}
void display() {
cout << "显示图片" << endl;
}
};
// 使用
Image* img = new Image("photo.jpg"); // 立即加载,可能卡顿
// 用户可能还没看这张图,就已经加载了,浪费资源
✅ 用代理模式
// 图片接口
class Image {
public:
virtual void display() = 0;
};
// 真实图片
class RealImage : public Image {
private:
string filename;
public:
RealImage(string f) : filename(f) {
loadFromDisk(filename); // 加载图片
}
void display() override {
cout << "显示图片" << endl;
}
};
// 代理:延迟加载
class ImageProxy : public Image {
private:
RealImage* realImage = nullptr;
string filename;
public:
ImageProxy(string f) : filename(f) {}
void display() override {
if (!realImage) {
realImage = new RealImage(filename); // 第一次显示时才加载
}
realImage->display();
}
};
// 使用
Image* img = new ImageProxy("photo.jpg"); // 不加载,很快
// ... 其他操作
img->display(); // 这时才加载图片
价值:延迟加载、控制访问、添加额外功能(如缓存、权限)
8. 外观模式 ⭐⭐⭐
偶尔考!常问与中介者模式的区别
一句话记住:复杂系统开个门
❌ 不用设计模式
// 用户要办一件简单的事,但系统很复杂
class User {
public:
void buyProduct() {
// 用户需要了解所有子系统
InventorySystem* inventory = new InventorySystem();
inventory->checkStock();
PaymentSystem* payment = new PaymentSystem();
payment->pay();
ShippingSystem* shipping = new ShippingSystem();
shipping->arrangeShipping();
NotificationSystem* notification = new NotificationSystem();
notification->sendSMS();
notification->sendEmail();
// 用户:我就想买个东西,为什么要懂这么多?
}
};
✅ 用外观模式
// 外观类:提供一个简单的入口
class OrderFacade {
private:
InventorySystem* inventory;
PaymentSystem* payment;
ShippingSystem* shipping;
NotificationSystem* notification;
public:
void placeOrder() {
inventory->checkStock();
payment->pay();
shipping->arrangeShipping();
notification->sendSMS();
notification->sendEmail();
}
};
// 使用
User user;
OrderFacade order;
order.placeOrder(); // 简单!用户不用了解子系统
价值:简化接口、解耦客户端和子系统、降低使用门槛
9. 组合模式 ⭐⭐⭐
偶尔考!常问树形结构处理
一句话记住:树形结构统一管
❌ 不用设计模式
// 文件系统:文件和文件夹
class File {
public:
string name;
void display() { cout << "文件: " << name << endl; }
};
class Folder {
public:
string name;
vector<File*> files;
vector<Folder*> folders; // 文件夹里可以有文件夹
void display() {
cout << "文件夹: " << name << endl;
for (auto f : files) f->display();
for (auto f : folders) f->display(); // 递归
}
// 问题:文件和文件夹是不同的类,处理时要分别对待
// 新增操作(如删除、复制)要改两个类
};
✅ 用组合模式
// 统一接口
class FileSystemNode {
public:
string name;
virtual void display() = 0;
virtual void add(FileSystemNode* node) {} // 文件不实现
};
// 文件
class File : public FileSystemNode {
public:
void display() override {
cout << "文件: " << name << endl;
}
};
// 文件夹
class Folder : public FileSystemNode {
private:
vector<FileSystemNode*> children;
public:
void display() override {
cout << "文件夹: " << name << endl;
for (auto c : children) c->display(); // 统一处理
}
void add(FileSystemNode* node) override {
children.push_back(node);
}
};
// 使用:统一对待文件和文件夹
Folder* root = new Folder();
root->add(new File());
root->add(new Folder());
root->display(); // 递归显示所有内容
价值:统一对待单个对象和组合对象、树形结构操作简化
三、行为型模式
10. 观察者模式 ⭐⭐⭐⭐⭐
面试必考!常问与发布-订阅模式的区别
一句话记住:一变多跟着变
❌ 不用设计模式
class User {
public:
void notify(string message) {
// 硬编码了所有通知方式
EmailSender::send(email, message);
SMSSender::send(phone, message);
WechatSender::send(openid, message);
// 新增通知方式?改这里!
}
};
// 问题:
// 1. User类和通知方式强耦合
// 2. 有些用户不想收邮件,怎么办?
// 3. 新增钉钉通知,要改User类
✅ 用观察者模式
// 观察者接口
class Observer {
public:
virtual void update(string message) = 0;
};
// 具体观察者
class EmailObserver : public Observer {
void update(string msg) override { /* 发邮件 */ }
};
class SMSObserver : public Observer {
void update(string msg) override { /* 发短信 */ }
};
// 主题
class User {
vector<Observer*> observers;
public:
void addObserver(Observer* o) { observers.push_back(o); }
void notify(string message) {
for (auto o : observers) {
o->update(message);
}
}
};
// 使用
User user;
user.addObserver(new EmailObserver()); // 用户想收邮件
user.addObserver(new SMSObserver()); // 用户想收短信
// user.addObserver(new DingTalkObserver()); // 新增钉钉,User类不用改!
user.notify("您有新订单");
价值:解耦主题和观察者、灵活增删观察者、支持广播通信
11. 策略模式 ⭐⭐⭐⭐⭐
面试必考!消除if-else的经典方案
一句话记住:算法随便换
❌ 不用设计模式
class PaymentSystem {
public:
void pay(string type, double amount) {
if (type == "alipay") {
cout << "支付宝支付 " << amount << "元" << endl;
} else if (type == "wechat") {
cout << "微信支付 " << amount << "元" << endl;
} else if (type == "creditcard") {
cout << "银行卡支付 " << amount << "元" << endl;
}
// 每次新增支付方式,都要改这里!
}
};
// 问题:
// 1. if-else越来越长
// 2. 违反开闭原则
// 3. 难以单独测试每种支付方式
✅ 用策略模式
// 支付策略接口
class PaymentStrategy {
public:
virtual void pay(double amount) = 0;
};
class Alipay : public PaymentStrategy {
void pay(double amount) override {
cout << "支付宝支付 " << amount << "元" << endl;
}
};
class WechatPay : public PaymentStrategy {
void pay(double amount) override {
cout << "微信支付 " << amount << "元" << endl;
}
};
// 新增支付方式?只需新建一个类!
class ApplePay : public PaymentStrategy {
void pay(double amount) override {
cout << "Apple Pay支付 " << amount << "元" << endl;
}
};
// 支付系统
class PaymentSystem {
private:
PaymentStrategy* strategy;
public:
void setStrategy(PaymentStrategy* s) { strategy = s; }
void pay(double amount) { strategy->pay(amount); }
};
// 使用
PaymentSystem ps;
ps.setStrategy(new Alipay());
ps.pay(100); // 支付宝支付
ps.setStrategy(new ApplePay()); // 切换策略
ps.pay(200); // Apple Pay支付
价值:消除if-else、算法可互换、易扩展新策略
12. 状态模式 ⭐⭐⭐⭐
常考!常问与策略模式的区别
一句话记住:状态决定行为
❌ 不用设计模式
class Order {
string status; // "pending", "paid", "shipped", "completed"
public:
void pay() {
if (status == "pending") {
status = "paid";
cout << "支付成功" << endl;
} else if (status == "paid") {
cout << "已支付,不能重复支付" << endl;
} else if (status == "shipped") {
cout << "已发货,不能支付" << endl;
}
// ... 每个方法都要写一堆if-else
}
void ship() {
if (status == "pending") {
cout << "未支付,不能发货" << endl;
} else if (status == "paid") {
status = "shipped";
cout << "发货成功" << endl;
}
// ...
}
// 新增状态?每个方法都要改!
};
✅ 用状态模式
// 状态接口
class OrderState {
public:
virtual void pay(Order* order) { cout << "当前状态不支持支付" << endl; }
virtual void ship(Order* order) { cout << "当前状态不支持发货" << endl; }
};
// 具体状态
class PendingState : public OrderState {
public:
void pay(Order* order) override {
cout << "支付成功" << endl;
order->setState(new PaidState());
}
};
class PaidState : public OrderState {
public:
void ship(Order* order) override {
cout << "发货成功" << endl;
order->setState(new ShippedState());
}
};
// 订单类
class Order {
OrderState* state;
public:
void setState(OrderState* s) { state = s; }
void pay() { state->pay(this); }
void ship() { state->ship(this); }
};
// 使用
Order order;
order.setState(new PendingState());
order.pay(); // 支付成功
order.ship(); // 发货成功
order.pay(); // 当前状态不支持支付
价值:消除if-else、状态逻辑清晰、易扩展新状态
13. 责任链模式 ⭐⭐⭐⭐
常考!常问与装饰器模式的区别
一句话记住:一个一个传
❌ 不用设计模式
void approve(int amount) {
if (amount <= 1000) {
cout << "组长审批通过" << endl;
} else if (amount <= 5000) {
cout << "组长同意,转经理..." << endl;
cout << "经理审批通过" << endl;
} else if (amount <= 10000) {
cout << "组长同意,转经理..." << endl;
cout << "经理同意,转总监..." << endl;
cout << "总监审批通过" << endl;
} else {
cout << "组长同意,转经理..." << endl;
cout << "经理同意,转总监..." << endl;
cout << "总监同意,转CEO..." << endl;
cout << "CEO审批通过" << endl;
}
// 新增审批人?改这里!逻辑越来越复杂!
}
✅ 用责任链模式
class Approver {
protected:
Approver* next;
int limit;
string name;
public:
void setNext(Approver* n) { next = n; }
void approve(int amount) {
if (amount <= limit) {
cout << name << "审批通过" << endl;
} else if (next) {
cout << name << "同意,转上级..." << endl;
next->approve(amount);
}
}
};
// 使用:像链条一样串起来
Approver* leader = new Approver{1000, "组长"};
Approver* manager = new Approver{5000, "经理"};
Approver* director = new Approver{10000, "总监"};
Approver* ceo = new Approver{999999, "CEO"};
leader->setNext(manager);
manager->setNext(director);
director->setNext(ceo);
leader->approve(500); // 组长审批通过
leader->approve(3000); // 组长同意,转上级... 经理审批通过
leader->approve(20000); // 一路转上去,CEO审批通过
价值:逻辑清晰、易扩展、解耦审批者
14. 模板模式 ⭐⭐⭐⭐
常考!常问与策略模式的区别
一句话记住:骨架固定细节变
❌ 不用设计模式
class DataExporter {
public:
void exportToCSV(Data data) {
openFile();
writeHeader("csv");
writeData(data, "csv");
closeFile();
}
void exportToJSON(Data data) {
openFile();
writeHeader("json");
writeData(data, "json");
closeFile();
}
void exportToXML(Data data) {
openFile();
writeHeader("xml");
writeData(data, "xml");
closeFile();
}
// 每个方法都有重复的 openFile、closeFile
// 新增格式?复制粘贴再改?
};
✅ 用模板模式
class DataExporter {
public:
// 模板方法:定义骨架
void export(Data data) {
openFile();
writeHeader();
writeData(data); // 子类实现
closeFile();
}
protected:
void openFile() { cout << "打开文件" << endl; }
void closeFile() { cout << "关闭文件" << endl; }
virtual void writeHeader() = 0;
virtual void writeData(Data data) = 0;
};
// CSV导出
class CSVExporter : public DataExporter {
void writeHeader() override { cout << "写CSV表头" << endl; }
void writeData(Data data) override { cout << "写CSV数据" << endl; }
};
// JSON导出
class JSONExporter : public DataExporter {
void writeHeader() override { cout << "写JSON头部" << endl; }
void writeData(Data data) override { cout << "写JSON数据" << endl; }
};
// 使用
DataExporter* exporter = new CSVExporter();
exporter->export(data); // 自动调用模板流程
价值:复用公共代码、只改差异部分、流程统一
15. 命令模式 ⭐⭐⭐
偶尔考!常问撤销操作的实现
一句话记住:操作封装成对象
❌ 不用设计模式
// 遥控器控制多个电器
class RemoteControl {
public:
void buttonPressed(int button) {
if (button == 1) {
light->on();
} else if (button == 2) {
light->off();
} else if (button == 3) {
tv->on();
} else if (button == 4) {
tv->off();
}
// 新增电器?改这里!
// 想要撤销操作?怎么记录之前的状态?
}
};
// 问题:
// 1. 遥控器和电器强耦合
// 2. 难以实现撤销操作
// 3. 难以实现宏命令(一键执行多个操作)
✅ 用命令模式
// 命令接口
class Command {
public:
virtual void execute() = 0;
virtual void undo() = 0; // 撤销
};
// 开灯命令
class LightOnCommand : public Command {
private:
Light* light;
public:
void execute() override { light->on(); }
void undo() override { light->off(); }
};
// 关灯命令
class LightOffCommand : public Command {
private:
Light* light;
public:
void execute() override { light->off(); }
void undo() override { light->on(); }
};
// 遥控器
class RemoteControl {
private:
Command* command;
vector<Command*> history; // 历史命令,用于撤销
public:
void setCommand(Command* c) { command = c; }
void pressButton() {
command->execute();
history.push_back(command);
}
void pressUndo() {
if (!history.empty()) {
history.back()->undo();
history.pop_back();
}
}
};
// 使用
RemoteControl remote;
remote.setCommand(new LightOnCommand());
remote.pressButton(); // 开灯
remote.pressUndo(); // 撤销:关灯
价值:解耦调用者和执行者、支持撤销、支持宏命令
16. 迭代器模式 ⭐⭐⭐
偶尔考!常问为什么需要迭代器
一句话记住:遍历不用管内部
❌ 不用设计模式
// 自定义集合
class MyList {
private:
int* data;
int size;
public:
int* getData() { return data; } // 暴露内部结构
int getSize() { return size; }
};
// 遍历:需要了解内部结构
MyList list;
for (int i = 0; i < list.getSize(); i++) {
cout << list.getData()[i] << endl;
}
// 问题:
// 1. 暴露了内部实现
// 2. 不同集合遍历方式不同,客户端要记住
// 3. 如果内部实现改了(比如改成链表),客户端代码要改
✅ 用迭代器模式
// 迭代器接口
class Iterator {
public:
virtual bool hasNext() = 0;
virtual int next() = 0;
};
// 集合接口
class Aggregate {
public:
virtual Iterator* createIterator() = 0;
};
// 具体迭代器
class MyListIterator : public Iterator {
private:
MyList* list;
int index;
public:
bool hasNext() override { return index < list->size; }
int next() override { return list->data[index++]; }
};
// 使用:统一遍历方式
Iterator* it = list->createIterator();
while (it->hasNext()) {
cout << it->next() << endl;
}
// 不管内部是数组、链表还是树,遍历方式都一样!
价值:隐藏内部结构、统一遍历接口、支持多种遍历方式
17. 中介者模式 ⭐⭐
很少考!了解即可
一句话记住:大家都找中介聊
❌ 不用设计模式
// 聊天室:用户之间直接通信
class User {
public:
void sendMessage(User* to, string msg) {
to->receiveMessage(this, msg);
}
void receiveMessage(User* from, string msg) {
cout << name << "收到" << from->name << "的消息:" << msg << endl;
}
};
// 问题:
// 1. 用户之间强耦合
// 2. 新增功能(如群发、过滤)要改User类
// 3. 用户数量多时,关系复杂
✅ 用中介者模式
// 中介者
class ChatRoom {
public:
void sendMessage(User* from, User* to, string msg) {
// 可以在这里加逻辑:过滤、记录、转发等
cout << from->name << " -> " << to->name << ": " << msg << endl;
}
void broadcast(User* from, string msg) {
cout << from->name << "广播: " << msg << endl;
}
};
// 用户
class User {
private:
ChatRoom* chatRoom;
public:
void sendMessage(User* to, string msg) {
chatRoom->sendMessage(this, to, msg); // 通过中介者
}
void broadcast(string msg) {
chatRoom->broadcast(this, msg);
}
};
// 使用
User* alice = new User("Alice");
User* bob = new User("Bob");
alice->sendMessage(bob, "你好"); // 通过聊天室转发
alice->broadcast("大家好"); // 广播
价值:解耦对象之间的关系、集中管理交互逻辑、易于扩展
18. 桥接模式 ⭐⭐⭐
偶尔考!常问与适配器模式的区别
一句话记住:抽象和实现分离
❌ 不用设计模式
// 图形和颜色的组合
class RedCircle {};
class BlueCircle {};
class RedSquare {};
class BlueSquare {};
// 问题:
// 形状 x 颜色 = 类爆炸!
// 新增形状或颜色,类数量指数增长
✅ 用桥接模式
// 颜色接口
class Color {
public:
virtual string getName() = 0;
};
class Red : public Color {
string getName() override { return "红色"; }
};
class Blue : public Color {
string getName() override { return "蓝色"; }
};
// 形状(桥接颜色)
class Shape {
protected:
Color* color;
public:
Shape(Color* c) : color(c) {}
virtual void draw() = 0;
};
class Circle : public Shape {
public:
Circle(Color* c) : Shape(c) {}
void draw() override {
cout << "画一个" << color->getName() << "的圆" << endl;
}
};
class Square : public Shape {
public:
Square(Color* c) : Shape(c) {}
void draw() override {
cout << "画一个" << color->getName() << "的方" << endl;
}
};
// 使用
Shape* shape = new Circle(new Red());
shape->draw(); // 画一个红色的圆
价值:避免类爆炸、抽象和实现独立变化、灵活组合
19. 享元模式 ⭐⭐
很少考!了解即可
一句话记住:共享细粒度对象
❌ 不用设计模式
// 棋盘上的棋子
class ChessPiece {
public:
string color; // 黑/白
string type; // 车/马/炮/兵...
int x, y; // 位置
ChessPiece(string c, string t, int x, int y)
: color(c), type(t), x(x), y(y) {}
};
// 32个棋子,每个都存储color和type
// 但color只有2种,type只有7种,重复存储浪费内存
✅ 用享元模式
// 共享部分(内部状态)
class ChessPieceType {
public:
string color; // 黑/白
string type; // 车/马/炮/兵...
};
// 享元工厂
class ChessFactory {
private:
map<string, ChessPieceType*> types;
public:
ChessPieceType* getType(string color, string type) {
string key = color + type;
if (types.find(key) == types.end()) {
types[key] = new ChessPieceType{color, type};
}
return types[key];
}
};
// 棋子(只存储外部状态)
class ChessPiece {
public:
ChessPieceType* type; // 共享
int x, y; // 不共享
};
// 使用:32个棋子,但只有7种类型对象
ChessFactory factory;
ChessPiece* piece1 = new ChessPiece{factory.getType("黑", "车"), 0, 0};
ChessPiece* piece2 = new ChessPiece{factory.getType("黑", "车"), 0, 9};
// 两个黑车共享同一个type对象
价值:减少内存占用、共享不变部分、适合大量细粒度对象
20. 备忘录模式 ⭐⭐
很少考!了解即可
一句话记住:保存状态好撤销
❌ 不用设计模式
// 游戏角色
class GameRole {
public:
int hp;
int mp;
int level;
void save() {
// 手动保存到文件或数据库
// 问题:暴露了内部状态
// 问题:保存逻辑和业务逻辑混在一起
}
void load() {
// 手动加载
}
};
✅ 用备忘录模式
// 备忘录:保存状态
class Memento {
public:
int hp;
int mp;
int level;
Memento(int h, int m, int l) : hp(h), mp(m), level(l) {}
};
// 游戏角色
class GameRole {
public:
int hp = 100;
int mp = 50;
int level = 1;
Memento* save() {
return new Memento(hp, mp, level);
}
void restore(Memento* m) {
hp = m->hp;
mp = m->mp;
level = m->level;
}
};
// 管理者
class Caretaker {
private:
vector<Memento*> history;
public:
void addMemento(Memento* m) { history.push_back(m); }
Memento* getMemento(int index) { return history[index]; }
};
// 使用
GameRole role;
Caretaker caretaker;
caretaker.addMemento(role.save()); // 保存状态
role.hp = 50; // 状态改变
role.restore(caretaker.getMemento(0)); // 恢复状态
价值:不暴露内部状态、支持撤销、状态管理独立
21. 访问者模式 ⭐⭐
很少考!了解即可
一句话记住:操作和数据分离
❌ 不用设计模式
// 文件系统
class File {
public:
string name;
int size;
void exportXML() { /* 导出XML */ }
void exportJSON() { /* 导出JSON */ }
void analyze() { /* 分析 */ }
// 新增操作?改File类!
};
// 问题:
// 1. 操作和数据混在一起
// 2. 新增操作要改所有元素类
✅ 用访问者模式
// 访问者接口
class Visitor {
public:
virtual void visit(File* file) = 0;
virtual void visit(Folder* folder) = 0;
};
// 具体访问者
class XMLExportVisitor : public Visitor {
public:
void visit(File* file) override {
cout << "导出文件XML: " << file->name << endl;
}
void visit(Folder* folder) override {
cout << "导出文件夹XML: " << folder->name << endl;
}
};
class JSONExportVisitor : public Visitor {
public:
void visit(File* file) override {
cout << "导出文件JSON: " << file->name << endl;
}
void visit(Folder* folder) override {
cout << "导出文件夹JSON: " << folder->name << endl;
}
};
// 元素接口
class Element {
public:
virtual void accept(Visitor* v) = 0;
};
// 具体元素
class File : public Element {
public:
string name;
void accept(Visitor* v) override { v->visit(this); }
};
// 使用
File* file = new File();
file->accept(new XMLExportVisitor()); // 导出XML
file->accept(new JSONExportVisitor()); // 导出JSON
// 新增操作?新建一个Visitor类,不用改File!
价值:操作和数据分离、易扩展新操作、符合单一职责
22. 解释器模式 ⭐
几乎不考!了解即可
一句话记住:实现一个小语言
❌ 不用设计模式
// 计算器:解析表达式 "1 + 2 + 3"
int calculate(string expr) {
// 硬编码解析逻辑
// 只能处理特定格式
// 难以扩展新的运算符
}
✅ 用解释器模式
// 表达式接口
class Expression {
public:
virtual int interpret() = 0;
};
// 数字表达式
class Number : public Expression {
private:
int value;
public:
Number(int v) : value(v) {}
int interpret() override { return value; }
};
// 加法表达式
class Add : public Expression {
private:
Expression* left;
Expression* right;
public:
Add(Expression* l, Expression* r) : left(l), right(r) {}
int interpret() override {
return left->interpret() + right->interpret();
}
};
// 使用:构建语法树
Expression* expr = new Add(
new Number(1),
new Add(new Number(2), new Number(3))
);
cout << expr->interpret() << endl; // 6
价值:易于扩展新语法、符合开闭原则、适合简单语言解析
四、一句话记住设计模式
// 聊天室:用户之间直接通信
class User {
public:
void sendMessage(User* to, string msg) {
to->receiveMessage(this, msg);
}
void receiveMessage(User* from, string msg) {
cout << name << "收到" << from->name << "的消息:" << msg << endl;
}
};
// 问题:
// 1. 用户之间强耦合
// 2. 新增功能(如群发、过滤)要改User类
// 3. 用户数量多时,关系复杂
✅ 用中介者模式
// 中介者
class ChatRoom {
public:
void sendMessage(User* from, User* to, string msg) {
// 可以在这里加逻辑:过滤、记录、转发等
cout << from->name << " -> " << to->name << ": " << msg << endl;
}
void broadcast(User* from, string msg) {
cout << from->name << "广播: " << msg << endl;
}
};
// 用户
class User {
private:
ChatRoom* chatRoom;
public:
void sendMessage(User* to, string msg) {
chatRoom->sendMessage(this, to, msg); // 通过中介者
}
void broadcast(string msg) {
chatRoom->broadcast(this, msg);
}
};
// 使用
User* alice = new User("Alice");
User* bob = new User("Bob");
alice->sendMessage(bob, "你好"); // 通过聊天室转发
alice->broadcast("大家好"); // 广播
价值:解耦对象之间的关系、集中管理交互逻辑、易于扩展
四、一句话记住设计模式
创建型模式
| 模式 | 面试热度 | 一句话记住 | 解决的问题 |
|---|---|---|---|
| 单例模式 | ⭐⭐⭐⭐⭐ 必考 | 全局只要一个 | 多实例浪费资源 |
| 工厂模式 | ⭐⭐⭐⭐⭐ 必考 | 创建逻辑集中管 | 创建逻辑分散 |
| 建造者模式 | ⭐⭐⭐⭐ 常考 | 复杂对象一步步建 | 参数过多难管理 |
| 原型模式 | ⭐⭐⭐ 偶尔考 | 复制比创建快 | 创建成本高 |
结构型模式
| 模式 | 面试热度 | 一句话记住 | 解决的问题 |
|---|---|---|---|
| 适配器模式 | ⭐⭐⭐⭐⭐ 必考 | 老代码包一层 | 接口不兼容 |
| 装饰器模式 | ⭐⭐⭐⭐⭐ 必考 | 层层包装加功能 | 继承爆炸 |
| 代理模式 | ⭐⭐⭐⭐⭐ 必考 | 找个中间人办事 | 控制访问、延迟加载 |
| 外观模式 | ⭐⭐⭐ 偶尔考 | 复杂系统开个门 | 接口太复杂 |
| 组合模式 | ⭐⭐⭐ 偶尔考 | 树形结构统一管 | 单个和组合处理不同 |
| 桥接模式 | ⭐⭐⭐ 偶尔考 | 抽象和实现分离 | 类爆炸 |
| 享元模式 | ⭐⭐ 很少考 | 共享细粒度对象 | 内存占用大 |
行为型模式
| 模式 | 面试热度 | 一句话记住 | 解决的问题 |
|---|---|---|---|
| 观察者模式 | ⭐⭐⭐⭐⭐ 必考 | 一变多跟着变 | 强耦合、难以通知 |
| 策略模式 | ⭐⭐⭐⭐⭐ 必考 | 算法随便换 | if-else地狱 |
| 状态模式 | ⭐⭐⭐⭐ 常考 | 状态决定行为 | 状态判断复杂 |
| 责任链模式 | ⭐⭐⭐⭐ 常考 | 一个一个传 | 层层嵌套 |
| 模板模式 | ⭐⭐⭐⭐ 常考 | 骨架固定细节变 | 重复代码 |
| 命令模式 | ⭐⭐⭐ 偶尔考 | 操作封装成对象 | 难以撤销、难解耦 |
| 迭代器模式 | ⭐⭐⭐ 偶尔考 | 遍历不用管内部 | 暴露内部结构 |
| 中介者模式 | ⭐⭐ 很少考 | 大家都找中介聊 | 对象关系复杂 |
| 备忘录模式 | ⭐⭐ 很少考 | 保存状态好撤销 | 难以恢复状态 |
| 访问者模式 | ⭐⭐ 很少考 | 操作和数据分离 | 操作和数据耦合 |
| 解释器模式 | ⭐ 几乎不考 | 实现一个小语言 | 语法解析复杂 |
五、什么时候用设计模式?
✅ 需要用
- 代码经常变化
- 逻辑分支很多(if-else地狱)
- 创建逻辑复杂
- 类之间耦合严重
- 需要扩展性
❌ 不需要用
- 简单的CRUD
- 代码写完就不改了
- 项目很小
- 过度设计反而累赘
六、设计模式核心思想
设计模式解决的是"变化"的问题:
1. 需求会变 → 用策略模式,新增策略即可
2. 实现会变 → 用工厂模式,切换实现只需改一处
3. 依赖会变 → 用观察者模式,解耦依赖关系
4. 状态会变 → 用状态模式,状态独立管理
5. 组合会变 → 用装饰器模式,自由组合功能
设计模式 = 应对变化的套路
设计原则 = 指导设计的思想
记住:设计模式不是银弹,而是工具!
文档版本:v1.0
创建时间:2026-04-07
适用范围:120天计划设计模式专项学习