C++常用设计模式详解

前言:本文详细解释几种常用的C++设计模式,都是平时项目中用的比较多的。本文针对每种设计模式都给出了示例,让你跟着代码彻底搞懂设计模式。

Tips:如果是准备面试,不需要知道所有的设计模式,要深入理解下面几种常用即可,因为面试官会先问你了解哪些设计模式,然后从你了解的里面挑一个深问,而且很有可能还会让你手撕出来。而且,最好提前准备一下自己的项目中哪里用到了你说的设计模式,面试官也可能会问。


C++常用设计模式

单例模式

单例模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例。主要用于控制全局资源,如日志管理器、线程池、配置管理器等。

实现方式:

  • 构造函数为私有,防止外部创建对象。
  • 提供一个静态方法,负责创建或获取该类的唯一实例。
  • 确保线程安全性。
class Singleton {
private:
    Singleton() {}

public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }

    // 禁止拷贝和赋值操作
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

C++11规定了局部静态变量在多线程条件下的初始化行为,要求编译器保证了局部静态变量的线程安全性。这样,只有当第一次访问getInstance()方法时才创建实例。C++11之后该实现是线程安全的,C++11之前仍需加锁。

工厂模式

用于创建对象(产品类)的接口,而不暴露对象创建的具体逻辑。适合于需要创建多个相似对象的场景,比如:图形界面组件、数据库连接。

简单工厂模式

建⽴⼀个⼯⼚类,对实现了同⼀接⼝的⼀些类(产品类)进⾏实例的创建。简单⼯⼚模式的实质是由⼀个⼯⼚类根据传⼊的参数,动态决定应该创建哪⼀个产品类(这些产品类继承⾃⼀个⽗类或接⼝)的实例。

// 产品类(抽象类,不能实例化)
class Product {
public:
    virtual void show() = 0;
};

class ConcreteProductA : public Product {
public:
    void show() override { std::cout << "Product A\n"; }
};

class ConcreteProductB : public Product {
public:
    void show() override { std::cout << "Product B\n"; }
};

// ⼯⼚类
class Factory {
public:
	Product* product(const string str){
		if (str == "productA")
			return new ConcreteProductA();
		if (str == "productB")
			return new ConcreteProductB();
		return nullptr;
	};
};

抽象工厂模式

为了进⼀步解耦,在简单⼯⼚的基础上发展出了抽象⼯⼚模式,即连⼯⼚都抽象出来,实现了进⼀步代码解耦。通过定义一个用于创建对象的接口,让工厂子类决定实例化哪个类。工厂模式的核心思想是将对象的创建和使用分离,以提高灵活性和扩展性。

实现方式:

  • 定义一个工厂基类,声明一个创建产品的接口。
  • 工厂子类实现这个接口,负责具体产品的创建。
class Product {
public:
    virtual void show() = 0;
};

class ConcreteProductA : public Product {
public:
    void show() override { std::cout << "Product A\n"; }
};

class ConcreteProductB : public Product {
public:
    void show() override { std::cout << "Product B\n"; }
};

class Factory {
public:
    virtual Product* createProduct() = 0;
};

class ConcreteFactoryA : public Factory {
public:
    Product* createProduct() override {
        return new ConcreteProductA();
    }
};

class ConcreteFactoryB : public Factory {
public:
    Product* createProduct() override {
        return new ConcreteProductB();
    }
};

观察者模式

定义了对象之间一对多的依赖关系,让多个观察对象同时监听⼀个被观察对象,被观察对象状态发⽣变化时,会通知所有的观察对象,使他们能够更新⾃⼰的状态。该模式常用于事件驱动系统、消息发布-订阅系统。

观察者模式中存在两种⻆⾊:

  • 观察者:内部包含被观察者对象,当被观察者对象的状态发⽣变化时,更新自己的状态。(接收通知更新状态)
  • 被观察者:内部包含了所有观察者对象,当状态发⽣变化时通知所有的观察者更新自己的状态。(发送通知)

实现方式:

  • 定义一个被观察者(Subject)接口,允许添加、删除观察者。
  • 定义观察者接口,声明更新方法。
  • 被观察者在状态发生变化时,通知所有观察者调用更新方法。
// 观察者
class Observer {
public:
    virtual void update(int value) = 0;
};

class ConcreteObserver : public Observer {
private:
    int observerValue;
    
public:
	// 被观察者对象的状态发⽣变化时,更新自己的状态
    void update(int value) override {
        observerValue = value;
        std::cout << "Observer value updated to " << observerValue << "\n";
    }
};

// 被观察者
class Subject {
private:
    std::vector<Observer*> observers;	// 存放所有观察者
    int state;

public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }

    void setState(int value) {
        state = value;
        notify();
    }
	
	// 通知所有的观察者更新自己的状态
    void notify() {
        for (Observer* observer : observers) {
            observer->update(state);
        }
    }
};

装饰器模式

装饰器模式允许向现有对象动态地添加行为,而不影响其他同类对象。该模式通常用于给对象增加功能,同时保持对象的结构灵活可扩展。

实现方式:

  • 定义一个组件接口,声明可以被装饰的操作。
  • 具体组件类实现接口,执行基本操作。
  • 装饰器类持有组件的引用,并在执行基本操作时添加新的功能。
// 组件接口
class Component {
public:
    virtual void operation() = 0;
};

// 具体组件
class ConcreteComponent : public Component {
public:
    void operation() override {
        std::cout << "ConcreteComponent operation\n";
    }
};

// 抽象装饰类
class Decorator : public Component {
protected:
    Component* component;

public:
    Decorator(Component* comp) : component(comp) {}

    void operation() override {
        component->operation();
    }
};

// 具体装饰类
class ConcreteDecorator : public Decorator {
public:
    ConcreteDecorator(Component* comp) : Decorator(comp) {}

    void operation() override {
        Decorator::operation();
        std::cout << "ConcreteDecorator added operation\n";
    }
};

// 创建一个具体组件
Component* component = new ConcreteComponent();
// 装饰组件
Component* decorator = new ConcreteDecorator(component);

解释:通过具体装饰类传入原对象,并重写操作函数 operation() 来实现对象的功能扩展,ConcreteDecorator::operation 先执行对象原操作,再执行新扩展的功能。

策略模式

策略模式定义了一系列算法,将每个算法封装到一个独立的类中,使得它们可以相互替换。此模式允许算法的变化独立于使用它的客户端。常用于:算法选择、支付方式选择等。

实现方式:

  • 定义一个抽象策略接口,声明策略的操作。
  • 策略实现类负责具体的算法。
  • 上下文类负责持有策略并执行操作。
// 抽象策略接口
class Strategy {
public:
    virtual void execute() = 0;
};

// 策略实现类A
class ConcreteStrategyA : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy A\n";
    }
};
// 策略实现类B
class ConcreteStrategyB : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy B\n";
    }
};

// 上下文类
class Context {
private:
    Strategy* strategy;

public:
    Context(Strategy* strategy) : strategy(strategy) {}
	
	// 选取某种策略
    void setStrategy(Strategy* newStrategy) {
        strategy = newStrategy;
    }
	
	// 执行选取策略的操作
    void executeStrategy() {
        strategy->execute();
    }
};

代理模式

代理模式为其他对象提供一个代理,以控制对这个对象的访问。常见的应用场景包括虚拟代理(延迟加载)、远程代理(为远程对象提供本地代理),以及保护代理(控制对象的访问权限)。

实现方式:

  • 定义一个接口,声明需要被代理的操作。
  • 代理类实现接口,负责控制实际对象的访问。
  • 实际对象类实现接口,执行具体操作。
class Subject {
public:
    virtual void request() = 0;
};

// 实际对象类
class RealSubject : public Subject {
public:
    void request() override {
        std::cout << "RealSubject handling request\n";
    }
};

// 代理类
class Proxy : public Subject {
private:
    RealSubject* realSubject;

public:
    Proxy() : realSubject(nullptr) {}

    ~Proxy() {
        delete realSubject;
    }

    void request() override {
        if (!realSubject) {
            realSubject = new RealSubject();
        }
        std::cout << "Proxy handling request, forwarding to RealSubject...\n";
        realSubject->request();
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值