跳转至

设计模式

1. 工厂模式 - 工厂的魔力

工厂模式属于创建者模式,提供了一种创建对象的最佳方式。创建型模式关注对象的创建过程,在软件开发中应用非常广泛。创建型模式描述如何将对象的创建和使用分离,让用户在使用对象过程中无须关心对象的创建细节,从而降低系统耦合度,并且让系统易于修改和扩展。

工厂模式的实现方式有简单工厂模式、工厂方法模式、抽象工厂模式,每个实现方式都存在优和劣。

简单工厂模式与工厂模式的结构组成是:

  1. 工厂类:工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。(可分为抽象工厂和具体工厂)
  2. 抽象产品类:是具体产品类的继承的父类或实现的接口。
  3. 具体产品类:工厂类所创建的对象就是此具体产品实例。

以汽车厂为例:

Cars为汽车的抽象类(基类),接口函数为Show(),用于显示文本。

Benzi、Audi、Bmw为具体汽车品牌的类,它们都继承于Cars抽象类。

// 汽车抽象类
class Cars
{
public:
    virtual ~Cars() {}
    virtual void Show() = 0;
};

// 奔驰 - 具体产品的实现方法
class Benzi: public Cars
{
public:
    void Show()
    {
        std::cout << "我是Benzi" << std::endl;
    }
};

// 奥迪
class Audi: public Cars
{
public:
    void Show()
    {
        std::cout << "我是Audi" << std::endl;
    }
};

CarsFactory为工厂类,类里实现根据汽车类型创建对应产品对象的CreateCars(CARS_TYPE type)函数。

enum CARS_TYPE
{
    BENZI,
    AUDI
};

// 总车厂
class CarsFactory
{
public:
    // 根据鞋子类型创建对应的鞋子对象
    Cars *CreateCars(CARS_TYPE type)
    {
        switch (type)
        {
        case BENZI:
            return new Benzi();
            break;
        case AUDI:
            return new Audi();
            break;
        default:
            return NULL;
            break;
        }
    }
};

main函数,先是构造了工厂对象,然后创建指定类型的具体产品对象,然后输出对应文本。因为采用的是new的方式创建了对象,用完了要通过delete 释放资源资源。

int main()
{
    // 构造工厂对象
    CarsFactory carsFactory;

    // 从工厂对象创建benzi对象
    Cars *pBenzi = carsFactory.CreateCars(BENZI);
    if (pBenzi != NULL)
    {
        pBenzi->Show();

        // 释放资源
        delete pBenzi;
        pBenzi = NULL;
    }

    // 从工厂对象创建audi对象
    Cars *pAudi = carsFactory.CreateCars(AUDI);
    if (pAudi != NULL)
    {
        pAudi ->Show();

        // 释放资源
        delete pAudi ;
        pAudi = NULL;
    }

    return 0;
}

简单工厂模式的优点在于:

  • 工厂类提供创建具体产品的方法,并包含一定判断逻辑,客户不必参与产品的创建过程;
  • 客户只需要知道对应产品的参数即可,参数一般简单好记,如数字、字符或者字符串等。

2. 工厂方法模式 - 多样化的工厂

简单工厂模式存在最大的问题是违背了“开闭原则”,每当增加新的产品时,需要修改工厂类的逻辑。为了规避这种不足,同时很好的利用简单工厂模式的优点,这里介绍工厂方法模式。

工厂方法模式:定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。

#include <iostream>
#include <string>

// 产品基类
class Product {
public:
    virtual void use() = 0;
};

// 具体产品类 A
class ConcreteProductA : public Product {
public:
    void use() override {
        std::cout << "Using ConcreteProductA" << std::endl;
    }
};

// 具体产品类 B
class ConcreteProductB : public Product {
public:
    void use() override {
        std::cout << "Using ConcreteProductB" << std::endl;
    }
};

// 工厂基类
class Factory {
public:
    virtual Product* createProduct() = 0;
};

// 具体工厂类 A
class ConcreteFactoryA : public Factory {
public:
    Product* createProduct() override {
        return new ConcreteProductA();
    }
};

// 具体工厂类 B
class ConcreteFactoryB : public Factory {
public:
    Product* createProduct() override {
        return new ConcreteProductB();
    }
};

int main() {
    // 使用具体工厂 A 创建产品 A
    Factory* factoryA = new ConcreteFactoryA();
    Product* productA = factoryA->createProduct();
    productA->use();

    // 使用具体工厂 B 创建产品 B
    Factory* factoryB = new ConcreteFactoryB();
    Product* productB = factoryB->createProduct();
    productB->use();

    delete factoryA;
    delete productA;
    delete factoryB;
    delete productB;

    return 0;
}

相较简单工厂模式,工厂方法模式更加符合开闭原则。工厂方法是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。

3. 抽象工厂模式 - 创建产品族

汽车厂为了扩大业务,不只生产汽车了,还生产摩托车。抽象工厂模式可以创建多个工厂和多个产品族(相关的产品)。

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。

抽象工厂模式的组成:

  1. 抽象工厂类:工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
  2. 具体工厂类:继承于抽象工厂,实现创建对应具体产品对象的方式。
  3. 抽象产品类:它是具体产品继承的父类(基类)。
  4. 具体产品类:具体工厂所创建的对象,就是此类。

创建基类(抽象产品类):

// 汽车抽象类
class Cars
{
public:
    virtual ~Cars() {}
    virtual void Show() = 0;
};

// 奔驰
class BenziCar: public Cars
{
public:
    void Show()
    {
        std::cout << "我是Benzi car" << std::endl;
    }
};

// 摩托车抽象类
class Motors
{
public:
    virtual ~Motors() {}
    virtual void Show() = 0;
};

// 奔驰
class BenziMotor: public Motors
{
public:
    void Show()
    {
        std::cout << "我是Benzi motor" << std::endl;
    }
};

Factory为抽象工厂,提供了创建汽车CreateCars()和摩托车产品CreateMotors()对象的接口。

BenziProducer为具体工厂,实现了创建奔驰汽车和奔驰摩托车的方式。

// 总厂
class Factory
{
public:
    virtual Cars *CreateCars() = 0;
    virtual Motors *CreateMotors() = 0;
    virtual ~Factory() {}
};

// benzi生产者/生产链
class BenziProducer : public Factory
{
public:
    Cars *CreateCars()
    {
        return new BenziCar();
    }

    Motors *CreateMotors()
    {
        return new BenziMotor();
    }
};

main函数,构造benzi工厂对象,然后创建benzi产品族的汽车和摩托车对象。同样,对象不再使用时,需要手动释放资源。

int main()
{
    // ================ 生产Benzi流程 ==================== //
    // 生产线
    Factory *benziProducer = new BenziProducer();

    // 生产汽车
    Cars *benziCar = benziProducer ->CreateCars();
    // 生产摩托车
    Motors *benziMotor = benziProducer ->CreateMotors();

    benziCar->Show();
    benziMotor->Show();

    // 释放资源
    delete benziCar;
    delete benziMotor;
    delete benziProducer;

    return 0;
}

适用场景:

  1. 一系列/一族产品需要被同时使用时,适合使用抽象工厂模式;
  2. 产品结构稳定,设计完成之后不会向系统中新增或剔除某个产品。

4. 建造者模式 - 建造一座大楼需要

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式的结构包含以下几个角色:

  • 抽象建造者(AbstractBuilder):创建一个Product对象的各个部件指定的抽象接口;
  • 具体建造者(ConcreteBuilder):实现AbstractBuilder的接口,实现各个部件的具体构造方法和装配方法,并返回创建结果。
  • 产品(Product):具体的产品对象
  • 指挥者(Director): 构建一个使用Builder接口的对象,安排复杂对象的构建过程,客户端一般只需要与Director交互,指定建造者类型,然后通过构造函数或者setter方法将具体建造者对象传入Director。它主要作用是:隔离客户与对象的生产过程,并负责控制产品对象的生产过程
#include <iostream>
#include <string>

// 产品类
class Product {
public:
    void setPartA(const std::string& partA) {
        partA_ = partA;
    }

    void setPartB(const std::string& partB) {
        partB_ = partB;
    }

    void setPartC(const std::string& partC) {
        partC_ = partC;
    }

    void show() {
        std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;
    }

private:
    std::string partA_;
    std::string partB_;
    std::string partC_;
};

// 抽象建造者类
class Builder {
public:
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;
    virtual Product* getProduct() = 0;
};

// 具体建造者类 A
class ConcreteBuilderA : public Builder {
public:
    void buildPartA() override {
        product_->setPartA("PartA of Product A");
    }

    void buildPartB() override {
        product_->setPartB("PartB of Product A");
    }

    void buildPartC() override {
        product_->setPartC("PartC of Product A");
    }

    Product* getProduct() override {
        return product_;
    }

private:
    Product* product_ = new Product();
};

// 指挥者类
class Director {
public:
    void construct(Builder* builder) {
        builder->buildPartA();
        builder->buildPartB();
        builder->buildPartC();
    }
};

int main() {
    Director director;

    ConcreteBuilderA builderA;
    director.construct(&builderA);

    Product* productA = builderA.getProduct();
    productA->show();

    delete productA;

    return 0;
}

适用环境:
- 需要生成的产品对象有复杂的内部结构(通常包含多个成员变量);
- 产品对象内部属性有一定的生成顺序;
- 同一个创建流程适用于多种不同的产品。

5. 原型模式 - 对象原型与复制

原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。

原型式的结构包含以下几个角色:

  • 抽象原型类(AbstractPrototype):声明克隆clone自身的接口
  • 具体原型类(ConcretePrototype):实现clone接口
  • 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例

原型模式可以说是“复制”,即克隆,但这个复制不是代码的复制,而是将对象包含的所有属性都创建一份拷贝。但不同的复制操作,可能会产生两种不同的拷贝,即浅拷贝和深拷贝。

#include <iostream>

// 原型基类
class Prototype {
public:
    virtual Prototype* clone() = 0;
    virtual void show() = 0;
};

// 具体原型类 A
class ConcretePrototypeA : public Prototype {
public:
    Prototype* clone() override {
        return new ConcretePrototypeA(*this);
    }

    void show() override {
        std::cout << "ConcretePrototypeA" << std::endl;
    }
};

// 具体原型类 B
class ConcretePrototypeB : public Prototype {
public:
    Prototype* clone() override {
        return new ConcretePrototypeB(*this);
    }

    void show() override {
        std::cout << "ConcretePrototypeB" << std::endl;
    }
};

int main() {
    ConcretePrototypeA prototypeA;
    Prototype* clonedA = prototypeA.clone();
    clonedA->show();
    delete clonedA;

    ConcretePrototypeB prototypeB;
    Prototype* clonedB = prototypeB.clone();
    clonedB->show();
    delete clonedB;

    return 0;
}

适用环境:

  • 当创建新的对象实例较为复杂时,原型模式可以简化创建过程;
  • 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少几个的组合状态,通过复制原型对象得到新实例,比通过使用构造函数创建一个新实例会更加方便。

6. 单例模式 - 唯一实例

单例模式是指在整个系统生命周期内,保证一个类只能产生一个实例,确保该类的唯一性。

单例模式可以保证线程安全,即给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用。

单例模式可以分为懒汉式和饿汉式,两者之间的区别在于创建实例的时间不同。懒汉式只有使用时才会创建实例,这种情况要考虑线程安全;饿汉式初始化就会创建实例,需要时直接调用,不用考虑安全问题。

饿汉式实现:

头文件:

// 饿汉实现 /
class Singleton
{
public:
    // 获取单实例
    static Singleton* GetInstance();

    // 释放单实例,进程退出时调用
    static void deleteInstance();

    // 打印实例地址
    void Print();

private:
    // 将其构造和析构成为私有的, 禁止外部构造和析构
    Singleton();
    ~Singleton();

    // 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值
    Singleton(const Singleton &signal);
    const Singleton &operator=(const Singleton &signal);

private:
    // 唯一单实例对象指针
    static Singleton *g_pSingleton;
};

源文件:

// 代码一运行就初始化创建实例 ,本身就线程安全
Singleton* Singleton::g_pSingleton = new (std::nothrow) Singleton();

Singleton* Singleton::GetInstance()
{
    return g_pSingleton;
}

void Singleton::deleteInstance()
{
    if (g_pSingleton)
    {
        delete g_pSingleton;
        g_pSingleton = nullptr;
    }
}

void Singleton::Print()
{
    std::cout << "我的实例内存地址是:" << this << std::endl;
}

Singleton::Singleton()
{
    std::cout << "构造函数" << std::endl;
}

Singleton::~Singleton()
{
    std::cout << "析构函数" << std::endl;
}

main程序:

#include <iostream>
#include <memory>
#include <mutex>

class Singleton {
public:
    static std::shared_ptr<Singleton> getSingleton();

    void print() {
        std::cout << "Hello World." << std::endl;
    }

    ~Singleton() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

private:
    Singleton() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

static std::shared_ptr<Singleton> singleton = nullptr;
static std::once_flag singletonFlag;

std::shared_ptr<Singleton> Singleton::getSingleton() {
    std::call_once(singletonFlag, [&] {
        singleton = std::shared_ptr<Singleton>(new Singleton());
    });
    return singleton;
}

7. 适配器模式 - 接口的适配

适配器模式主要用于在不兼容的接口之间进行适配,使得它们可以协同工作。

#include <iostream>

// 目标接口类
class Target {
public:
    virtual void request() = 0;
};

// 源接口类
class Adaptee {
public:
    void specificRequest() {
        std::cout << "Adaptee's specific request" << std::endl;
    }
};

// 对象适配器类
class Adapter : public Target {
public:
    Adapter(Adaptee* adaptee) : adaptee_(adaptee) {}

    void request() override {
        adaptee_->specificRequest();
    }

private:
    Adaptee* adaptee_;
};

int main() {
    Adaptee adaptee;
    Adapter adapter(&adaptee);
    adapter.request();

    return 0;
}

8. 桥接模式 - 接口的连接

桥接模式主要用于将抽象部分和实现部分分离,使它们可以独立变化,降低它们之间的耦合性。

#include <iostream>

// 实现部分的接口
class Implementor {
public:
    virtual void operationImpl() = 0;
};

// 具体实现类 A
class ConcreteImplementorA : public Implementor {
public:
    void operationImpl() override {
        std::cout << "Concrete Implementor A operation" << std::endl;
    }
};

// 具体实现类 B
class ConcreteImplementorB : public Implementor {
public:
    void operationImpl() override {
        std::cout << "Concrete Implementor B operation" << std::endl;
    }
};

// 抽象部分的接口
class Abstraction {
public:
    Abstraction(Implementor* implementor) : implementor_(implementor) {}

    virtual void operation() {
        implementor_->operationImpl();
    }

protected:
    Implementor* implementor_;
};

// 扩展抽象类
class RefinedAbstraction : public Abstraction {
public:
    RefinedAbstraction(Implementor* implementor) : Abstraction(implementor) {}

    void otherOperation() {
        std::cout << "Other operation of Refined Abstraction" << std::endl;
    }
};

int main() {
    Implementor* implementorA = new ConcreteImplementorA();
    Implementor* implementorB = new ConcreteImplementorB();

    Abstraction* abstractionA = new Abstraction(implementorA);
    abstractionA->operation();

    Abstraction* abstractionB = new RefinedAbstraction(implementorB);
    abstractionB->operation();
    dynamic_cast<RefinedAbstraction*>(abstractionB)->otherOperation();

    delete implementorA;
    delete implementorB;
    delete abstractionA;
    delete abstractionB;

    return 0;
}

9. 观察者模式 - 对象随动变化

观察者模式的基本原理,通过观察者模式可以实现对象之间的松耦合,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并作出相应的响应。

#include <iostream>
#include <vector>

// 观察者基类
class Observer {
public:
    virtual void update(int data) = 0;
};

// 具体观察者类 A
class ConcreteObserverA : public Observer {
public:
    void update(int data) override {
        std::cout << "Concrete Observer A received data: " << data << std::endl;
    }
};

// 具体观察者类 B
class ConcreteObserverB : public Observer {
public:
    void update(int data) override {
        std::cout << "Concrete Observer B received data: " << data << std::endl;
    }
};

// 主题类
class Subject {
private:
    int data;
    std::vector<Observer*> observers;

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

    void setData(int newData) {
        data = newData;
        notify();
    }

    void notify() {
        for (Observer* observer : observers) {
            observer->update(data);
        }
    }
};

int main() {
    ConcreteObserverA observerA;
    ConcreteObserverB observerB;

    Subject subject;
    subject.attach(&observerA);
    subject.attach(&observerB);

    subject.setData(100);

    return 0;
}

10. 装饰者模式 - 增加一些功能

动态地给一个对象添加一些额外的职责,同时不改变其结构。

#include <iostream>

// 组件基类
class Component {
public:
    virtual void operation() = 0;
};

// 具体组件类
class ConcreteComponent : public Component {
public:
    void operation() override {
        std::cout << "Concrete Component Operation" << std::endl;
    }
};

// 装饰者基类
class Decorator : public Component {
protected:
    Component* component;

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

    void operation() override {
        if (component != nullptr) {
            component->operation();
        }
    }
};

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

    void addBehavior() {
        std::cout << "Added Behavior A" << std::endl;
    }

    void operation() override {
        Decorator::operation();
        addBehavior();
    }
};

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

    void addBehavior() {
        std::cout << "Added Behavior B" << std::endl;
    }

    void operation() override {
        Decorator::operation();
        addBehavior();
    }
};

int main() {
    ConcreteComponent* component = new ConcreteComponent();
    ConcreteDecoratorA* decoratorA = new ConcreteDecoratorA(component);
    ConcreteDecoratorB* decoratorB = new ConcreteDecoratorB(decoratorA);

    decoratorB->operation();

    delete decoratorB;
    delete decoratorA;
    delete component;

    return 0;
}

11. 策略模式 - 运行时选择行为

策略模式是一种行为设计模式,它允许在运行时选择算法的行为。定义一系列算法,把它们封装起来,并且使它们可以互相替换。策略模式可以使算法独立于使用它的客户端而变化。

#include <iostream>

// 策略接口
class Strategy {
public:
    virtual void execute() = 0;
};

// 具体策略 A
class ConcreteStrategyA : public Strategy {
public:
    void execute() override {
        std::cout << "Executing Concrete Strategy A" << std::endl;
    }
};

// 具体策略 B
class ConcreteStrategyB : public Strategy {
public:
    void execute() override {
        std::cout << "Executing Concrete Strategy B" << std::endl;
    }
};

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

public:
    Context(Strategy* s) : strategy(s) {}

    void setStrategy(Strategy* s) {
        strategy = s;
    }

    void executeStrategy() {
        strategy->execute();
    }
};

int main() {
    ConcreteStrategyA strategyA;
    ConcreteStrategyB strategyB;

    Context context(&strategyA);
    context.executeStrategy();

    context.setStrategy(&strategyB);
    context.executeStrategy();

    return 0;
}

12. 命令模式 - 参数化行为

命令模式是一种行为设计模式,它将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,队列或记录请求日志,以及支持可撤销的操作。

#include <iostream>
#include <vector>

// 命令接口
class Command {
public:
    virtual void execute() = 0;
};

// 具体命令类 A
class ConcreteCommandA : public Command {
public:
    void execute() override {
        std::cout << "Executing Concrete Command A" << std::endl;
    }
};

// 具体命令类 B
class ConcreteCommandB : public Command {
public:
    void execute() override {
        std::cout << "Executing Concrete Command B" << std::endl;
    }
};

// 执行命令的对象
class Invoker {
private:
    std::vector<Command*> commands;

public:
    void addCommand(Command* command) {
        commands.push_back(command);
    }

    void executeCommands() {
        for (Command* command : commands) {
            command->execute();
        }

        commands.clear();
    }
};

int main() {
    ConcreteCommandA commandA;
    ConcreteCommandB commandB;

    Invoker invoker;
    invoker.addCommand(&commandA);
    invoker.addCommand(&commandB);

    invoker.executeCommands();

    return 0;
}

13. 状态模式 - 状态随动改变

状态模式是一种行为设计模式,它允许对象在内部状态改变时改变它的行为。状态模式通过将状态封装成独立的类,并将行为委托给当前状态对象来实现。

#include <iostream>

// 状态接口
class State {
public:
    virtual void handle() = 0;
};

// 具体状态类 A
class ConcreteStateA : public State {
public:
    void handle() override {
        std::cout << "Handling in State A" << std::endl;
    }
};

// 具体状态类 B
class ConcreteStateB : public State {
public:
    void handle() override {
        std::cout << "Handling in State B" << std::endl;
    }
};

// 上下文类
class Context {
private:
    State* state;

public:
    Context(State* initialState) : state(initialState) {}

    void setState(State* newState) {
        state = newState;
    }

    void request() {
        state->handle();
    }
};

int main() {
    ConcreteStateA stateA;
    ConcreteStateB stateB;

    Context context(&stateA);
    context.request();

    context.setState(&stateB);
    context.request();

    return 0;
}

14. 模板方法 - 算法原型与修改

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。这样可以使子类在不改变算法结构的情况下重新定义某些步骤。

#include <iostream>

// 抽象类定义模板方法
class AbstractClass {
public:
    // 模板方法定义了算法的骨架
    void templateMethod() {
        step1();
        step2();
        step3();
    }

    virtual void step1() = 0; // 子类必须实现的步骤1
    virtual void step2() = 0; // 子类必须实现的步骤2

    void step3() {
        std::cout << "Abstract step3" << std::endl;
    }
};

// 具体子类实现具体步骤
class ConcreteClassA : public AbstractClass {
public:
    void step1() override {
        std::cout << "ConcreteClassA step1" << std::endl;
    }

    void step2() override {
        std::cout << "ConcreteClassA step2" << std::endl;
    }
};

class ConcreteClassB : public AbstractClass {
public:
    void step1() override {
        std::cout << "ConcreteClassB step1" << std::endl;
    }

    void step2() override {
        std::cout << "ConcreteClassB step2" << std::endl;
    }
};

int main() {
    AbstractClass* a = new ConcreteClassA();
    AbstractClass* b = new ConcreteClassB();

    a->templateMethod();
    b->templateMethod();

    delete a;
    delete b;

    return 0;
}

通过模板方法模式,我们可以在父类中定义一个算法的骨架,而将具体实现延迟到子类中,从而实现代码复用和扩展。

以上。