C++八股 —— 设计模式

文章目录

一、创建型模式

1. 单例模式

C++八股 ------ 单例模式_c++ 单例模式-CSDN博客

2. 工厂模式

参考:【设计模式】工厂模式详解-----简单工厂模式、工厂方法模式、抽象工厂模式-CSDN博客

什么是工厂模式

工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式,而无需暴露对象创建的逻辑细节。

工厂模式的三种类型

  1. 简单工厂模式:一个工厂类根据传入的参数决定创建哪种产品类的实例
  2. 工厂方法模式:定义一个创建对象的接口,但让子类决定实例化哪个类
  3. 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

工厂模式的优点

  1. 封装创建逻辑:将对象的创建与使用分离
  2. 代码解耦:客户端代码不需要知道具体产品类的类名
  3. 易于扩展:添加新产品时,只需扩展工厂类,符合开闭原则
  4. 统一管理:可以对对象的创建进行统一的管理和控制

适用场景

  1. 当一个类不知道它所必须创建的对象的类时
  2. 当一个类希望由其子类来指定它所创建的对象时
  3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化时

简单工程模式示例

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

// 产品接口
class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() {}
};

// 具体产品类
class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Rectangle" << std::endl;
    }
};

class Triangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Triangle" << std::endl;
    }
};

// 简单工厂
class ShapeFactory {
public:
    static std::unique_ptr<Shape> createShape(const std::string& shapeType) {
        if (shapeType == "CIRCLE") {
            return std::make_unique<Circle>();
        } else if (shapeType == "RECTANGLE") {
            return std::make_unique<Rectangle>();
        } else if (shapeType == "TRIANGLE") {
            return std::make_unique<Triangle>();
        }
        return nullptr;
    }
};

int main() {
    // 使用工厂创建对象
    auto circle = ShapeFactory::createShape("CIRCLE");
    auto rectangle = ShapeFactory::createShape("RECTANGLE");
    auto triangle = ShapeFactory::createShape("TRIANGLE");
    
    circle->draw();
    rectangle->draw();
    triangle->draw();
    
    return 0;
}

工厂方法模式

cpp 复制代码
#include <iostream>
#include <memory>

// 产品接口
class Button {
public:
    virtual void render() = 0;
    virtual void onClick() = 0;
    virtual ~Button() {}
};

// 具体产品
class WindowsButton : public Button {
public:
    void render() override {
        std::cout << "Rendering a Windows button" << std::endl;
    }
    
    void onClick() override {
        std::cout << "Windows button clicked" << std::endl;
    }
};

class WebButton : public Button {
public:
    void render() override {
        std::cout << "Rendering a Web button" << std::endl;
    }
    
    void onClick() override {
        std::cout << "Web button clicked" << std::endl;
    }
};

// 创建者类
class Dialog {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    
    void render() {
        auto button = createButton();
        button->render();
        button->onClick();
    }
    
    virtual ~Dialog() {}
};

// 具体创建者
class WindowsDialog : public Dialog {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }
};

class WebDialog : public Dialog {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WebButton>();
    }
};

int main() {
    std::unique_ptr<Dialog> dialog;
    
    // 根据配置或环境选择创建者
    std::string config = "Windows"; // 可以改为 "Web" 来测试
    
    if (config == "Windows") {
        dialog = std::make_unique<WindowsDialog>();
    } else if (config == "Web") {
        dialog = std::make_unique<WebDialog>();
    }
    
    if (dialog) {
        dialog->render();
    }
    
    return 0;
}

抽象工程模式

cpp 复制代码
#include <iostream>
#include <memory>

// 抽象产品A
class Checkbox {
public:
    virtual void paint() = 0;
    virtual ~Checkbox() {}
};

// 具体产品A1
class WindowsCheckbox : public Checkbox {
public:
    void paint() override {
        std::cout << "Rendering a Windows checkbox" << std::endl;
    }
};

// 具体产品A2
class WebCheckbox : public Checkbox {
public:
    void paint() override {
        std::cout << "Rendering a Web checkbox" << std::endl;
    }
};

// 抽象产品B
class Button {
public:
    virtual void paint() = 0;
    virtual ~Button() {}
};

// 具体产品B1
class WindowsButton : public Button {
public:
    void paint() override {
        std::cout << "Rendering a Windows button" << std::endl;
    }
};

// 具体产品B2
class WebButton : public Button {
public:
    void paint() override {
        std::cout << "Rendering a Web button" << std::endl;
    }
};

// 抽象工厂
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<Checkbox> createCheckbox() = 0;
    virtual ~GUIFactory() {}
};

// 具体工厂1
class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }
    
    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<WindowsCheckbox>();
    }
};

// 具体工厂2
class WebFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WebButton>();
    }
    
    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<WebCheckbox>();
    }
};

// 客户端代码
class Application {
private:
    std::unique_ptr<GUIFactory> factory;
    std::unique_ptr<Button> button;
    std::unique_ptr<Checkbox> checkbox;
    
public:
    Application(std::unique_ptr<GUIFactory> f) : factory(std::move(f)) {}
    
    void createUI() {
        button = factory->createButton();
        checkbox = factory->createCheckbox();
    }
    
    void paint() {
        if (button) button->paint();
        if (checkbox) checkbox->paint();
    }
};

int main() {
    std::string config = "Windows"; // 可以改为 "Web" 来测试
    
    std::unique_ptr<GUIFactory> factory;
    if (config == "Windows") {
        factory = std::make_unique<WindowsFactory>();
    } else if (config == "Web") {
        factory = std::make_unique<WebFactory>();
    }
    
    if (factory) {
        auto app = Application(std::move(factory));
        app.createUI();
        app.paint();
    }
    
    return 0;
}

二、结构型模式

1. 装饰器模式

核心思想动态地给一个对象添加一些额外的职责,而无需通过子类继承。它通过创建一个包装对象(即装饰器)来包裹真实对象,提供了比继承更有弹性的替代方案。

比喻:就像给一个礼物打包。你可以先装盒子,再系丝带,最后贴卡片。每个步骤都是在原有礼物的基础上"装饰"新的功能,而不是改变礼物本身。

优点

  • 无需创建大量子类即可扩展功能。
  • 可以在运行时动态地添加或撤销功能。
  • 符合"开闭原则"(对扩展开放,对修改关闭)。

C++ 样例

我们有一个简单的Stream接口,我们需要动态地为其添加压缩和加密的功能。

cpp 复制代码
#include <iostream>
#include <string>

// 组件接口
class Stream {
public:
    virtual void write(const std::string& data) = 0;
    virtual ~Stream() {}
};

// 具体组件
class FileStream : public Stream {
public:
    void write(const std::string& data) override {
        std::cout << "Writing \"" << data << "\" to a file." << std::endl;
    }
};

// 装饰器基类
class StreamDecorator : public Stream {
protected:
    Stream* m_stream; // 持有一个组件对象的引用
public:
    StreamDecorator(Stream* stream) : m_stream(stream) {}
    virtual ~StreamDecorator() { delete m_stream; }
};

// 具体装饰器 - 压缩
class CompressedStream : public StreamDecorator {
public:
    CompressedStream(Stream* stream) : StreamDecorator(stream) {}
    void write(const std::string& data) override {
        std::string compressedData = "Compressed(" + data + ")";
        m_stream->write(compressedData); // 调用被装饰对象的方法
    }
};

// 具体装饰器 - 加密
class EncryptedStream : public StreamDecorator {
public:
    EncryptedStream(Stream* stream) : StreamDecorator(stream) {}
    void write(const std::string& data) override {
        std::string encryptedData = "Encrypted(" + data + ")";
        m_stream->write(encryptedData); // 调用被装饰对象的方法
    }
};

int main() {
    // 1. 简单的文件流
    Stream* stream1 = new FileStream();
    stream1->write("Hello World");
    delete stream1;

    std::cout << "---------------" << std::endl;

    // 2. 动态添加功能:压缩的文件流
    Stream* stream2 = new CompressedStream(new FileStream());
    stream2->write("Hello World");
    delete stream2;

    std::cout << "---------------" << std::endl;

    // 3. 动态添加更多功能:先加密再压缩的文件流
    // 装饰顺序很重要!
    Stream* stream3 = new CompressedStream(new EncryptedStream(new FileStream()));
    stream3->write("Hello World");
    delete stream3;

    return 0;
}

输出

text 复制代码
Writing "Hello World" to a file.
---------------
Writing "Compressed(Hello World)" to a file.
---------------
Writing "Compressed(Encrypted(Hello World))" to a file.

2. 代理模式

核心思想:为另一个对象提供一个替身或占位符以控制对这个对象的访问。

常见代理类型

  • 远程代理:为一个对象在不同的地址空间提供局部代表(例如,RPC调用)。
  • 虚拟代理:根据需要创建开销很大的对象(如图片懒加载)。
  • 保护代理:控制对原始对象的访问权限。
  • 智能引用代理:在对象被访问时执行附加操作(如引用计数、日志记录)。

C++ 样例

虚拟代理:延迟加载大图片。

cpp 复制代码
#include <iostream>
#include <string>

// 抽象主题
class Image {
public:
    virtual void display() = 0;
    virtual ~Image() {}
};

// 真实主题
class RealImage : public Image {
private:
    std::string m_filename;
    void loadFromDisk() {
        std::cout << "Loading image: " << m_filename << " (This is an expensive operation!)" << std::endl;
    }
public:
    RealImage(const std::string& filename) : m_filename(filename) {
        loadFromDisk();
    }
    void display() override {
        std::cout << "Displaying image: " << m_filename << std::endl;
    }
};

// 代理
class ProxyImage : public Image {
private:
    std::string m_filename;
    RealImage* m_realImage; // 代理持有一个对真实对象的引用

public:
    ProxyImage(const std::string& filename) : m_filename(filename), m_realImage(nullptr) {}
    ~ProxyImage() { delete m_realImage; }

    void display() override {
        // 只有在需要时才创建真实对象
        if (m_realImage == nullptr) {
            m_realImage = new RealImage(m_filename);
        }
        // 委托给真实对象执行请求
        m_realImage->display();
    }
};

int main() {
    // 创建代理时,真实对象尚未创建,没有昂贵的加载操作
    Image* image = new ProxyImage("test_10MB_photo.jpg");

    std::cout << "Image object created. Image not loaded yet." << std::endl;

    // 第一次调用display,真实对象被创建和加载
    image->display();
    std::cout << std::endl;

    // 后续调用,真实对象已存在,直接使用
    std::cout << "Second display call:" << std::endl;
    image->display();

    delete image;
    return 0;
}

输出

text 复制代码
Image object created. Image not loaded yet.
Loading image: test_10MB_photo.jpg (This is an expensive operation!)
Displaying image: test_10MB_photo.jpg

Second display call:
Displaying image: test_10MB_photo.jpg

三、行为型模式

1. 观察者模式

核心思想:定义对象间的一种一对多的依赖关系,当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都得到通知并被自动更新。又称"发布-订阅"模式。

比喻:报纸订阅。出版社(主题)负责出版报纸。你(观察者)向出版社订阅后,一旦有新报纸出版,出版社就会自动送到你家。你也可以随时取消订阅。

C++ 样例

使用现代C++的特性实现。

cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

// 观察者接口
class Observer {
public:
    virtual void update(int temperature) = 0;
    virtual ~Observer() {}
};

// 主题(被观察者)
class WeatherStation {
private:
    int m_temperature;
    std::vector<Observer*> m_observers; // 存储观察者指针

public:
    void registerObserver(Observer* observer) {
        m_observers.push_back(observer);
    }

    void removeObserver(Observer* observer) {
        m_observers.erase(
            std::remove(m_observers.begin(), m_observers.end(), observer),
            m_observers.end()
        );
    }

    void notifyObservers() {
        for (auto observer : m_observers) {
            observer->update(m_temperature);
        }
    }

    void setTemperature(int temp) {
        m_temperature = temp;
        std::cout << "Temperature updated to: " << temp << std::endl;
        notifyObservers(); // 状态改变,通知所有观察者
    }
};

// 具体观察者
class Display : public Observer {
public:
    void update(int temperature) override {
        std::cout << "[Display] Current temperature is: " << temperature << "°C" << std::endl;
    }
};

class AlertSystem : public Observer {
public:
    void update(int temperature) override {
        if (temperature > 30) {
            std::cout << "[AlertSystem] Warning! Temperature is too high: " << temperature << "°C" << std::endl;
        }
    }
};

int main() {
    WeatherStation station;

    Display display;
    AlertSystem alert;

    // 注册观察者
    station.registerObserver(&display);
    station.registerObserver(&alert);

    // 改变主题状态,触发通知
    station.setTemperature(25);
    std::cout << "-------------------" << std::endl;
    station.setTemperature(35);

    // 移除一个观察者
    station.removeObserver(&alert);
    std::cout << "-------------------" << std::endl;
    std::cout << "After removing alert system:" << std::endl;
    station.setTemperature(40);

    return 0;
}

输出

text 复制代码
Temperature updated to: 25
[Display] Current temperature is: 25°C
[AlertSystem] Warning! Temperature is too high: 25°C
-------------------
Temperature updated to: 35
[Display] Current temperature is: 35°C
[AlertSystem] Warning! Temperature is too high: 35°C
-------------------
After removing alert system:
Temperature updated to: 40
[Display] Current temperature is: 40°C

2. 策略模式

核心思想:定义一系列算法,将每个算法封装起来,并且使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。

比喻:出行方式。去机场是一个目标(Context),你可以选择不同的策略(Strategy):坐公交、打车、坐地铁。你可以根据时间、金钱等因素轻松替换策略,而改变"去机场"这个行为本身。

优点

  • 避免使用多重条件判断语句(if-else/switch-case)。
  • 算法可以自由切换和扩展。
  • 符合"开闭原则"。

C++ 样例

cpp 复制代码
#include <iostream>
#include <memory>
#include <vector>

// 策略接口
class PaymentStrategy {
public:
    virtual void pay(int amount) = 0;
    virtual ~PaymentStrategy() {}
};

// 具体策略
class CreditCardPayment : public PaymentStrategy {
private:
    std::string m_name;
    std::string m_cardNumber;
public:
    CreditCardPayment(const std::string& name, const std::string& cardNumber)
        : m_name(name), m_cardNumber(cardNumber) {}
    void pay(int amount) override {
        std::cout << "Paid $" << amount << " using Credit Card (" << m_cardNumber << ")" << std::endl;
    }
};

class PayPalPayment : public PaymentStrategy {
private:
    std::string m_email;
public:
    PayPalPayment(const std::string& email) : m_email(email) {}
    void pay(int amount) override {
        std::cout << "Paid $" << amount << " using PayPal (" << m_email << ")" << std::endl;
    }
};

class CryptoPayment : public PaymentStrategy {
private:
    std::string m_walletAddress;
public:
    CryptoPayment(const std::string& address) : m_walletAddress(address) {}
    void pay(int amount) override {
        std::cout << "Paid $" << amount << " using Crypto (Address: " << m_walletAddress << ")" << std::endl;
    }
};

// 上下文(Context)
class ShoppingCart {
private:
    std::vector<std::string> m_items;
    std::unique_ptr<PaymentStrategy> m_paymentStrategy;

public:
    void addItem(const std::string& item) {
        m_items.push_back(item);
    }

    int calculateTotal() {
        // 简化计算,假设每件商品10美元
        return m_items.size() * 10;
    }

    void setPaymentStrategy(std::unique_ptr<PaymentStrategy> strategy) {
        m_paymentStrategy = std::move(strategy);
    }

    void checkout() {
        int amount = calculateTotal();
        if (m_paymentStrategy) {
            m_paymentStrategy->pay(amount);
            std::cout << "Checkout successful! Enjoy your items." << std::endl;
        } else {
            std::cout << "Please set a payment method before checkout." << std::endl;
        }
    }
};

int main() {
    ShoppingCart cart;
    cart.addItem("Book");
    cart.addItem("Laptop");
    cart.addItem("Mouse");

    int total = cart.calculateTotal();
    std::cout << "Total: $" << total << std::endl;

    // 用户在运行时选择支付策略
    int choice = 2; // 可以来自用户输入

    if (choice == 1) {
        cart.setPaymentStrategy(std::make_unique<CreditCardPayment>("John Doe", "1234-5678-9012-3456"));
    } else if (choice == 2) {
        cart.setPaymentStrategy(std::make_unique<PayPalPayment>("john.doe@example.com"));
    } else if (choice == 3) {
        cart.setPaymentStrategy(std::make_unique<CryptoPayment>("0xABC123..."));
    }

    cart.checkout();

    return 0;
}

输出

text 复制代码
Total: $30
Paid $30 using PayPal (john.doe@example.com)
Checkout successful! Enjoy your items.

注:以上内容大部分由DeepSeek生成