设计模式实战对比

6 阅读23分钟

设计模式实战对比

用"前后对比"的方式,让你真切感受每个设计模式的价值

面试热度标记:⭐⭐⭐⭐⭐ 必考 | ⭐⭐⭐⭐ 常考 | ⭐⭐⭐ 偶尔考 | ⭐⭐ 很少考


目录


一、创建型模式

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天计划设计模式专项学习