1. 单例模式
1.1 什么是单例设计模式
单例模式是⼀种创建型设计模式, 它的核⼼思想是保证⼀个类只有⼀个实例,并提供⼀个全局访问点来访问这个实例。
- 只有⼀个实例的意思是,在整个应⽤程序中,只存在该类的⼀个实例对象,⽽不是创建多个相同类型的对象。
- 全局访问点的意思是,为了让其他类能够获取到这个唯⼀实例,该类提供了⼀个全局访问点(通常是⼀个静态⽅法),通过这个⽅法就能获得实例。
1.2为什么要使用单例设计模式呢
简易来说,单例设计模式有以下⼏个优点让我们考虑使⽤它:
- 全局控制:保证只有⼀个实例,这样就可以严格的控制客户怎样访问它以及何时访问它,简单的说就是对唯⼀实例的受控访问(引⽤⾃《⼤话设计模式》第21章)
- 节省资源:也正是因为只有⼀个实例存在,就避免多次创建了相同的对象,从⽽节省了系统资源,⽽且多个模块还可以通过单例实例共享数据。
- 懒加载:单例模式可以实现懒加载,只有在需要时才进⾏实例化,这⽆疑会提⾼程序的性能。
1.3 单例设计模式的基本要求
想要实现⼀个单例设计模式,必须遵循以下规则:
- 私有的构造函数:防⽌外部代码直接创建类的实例私有的静态实例变量:保存该类的唯⼀实例
- 公有的静态⽅法:通过公有的静态⽅法来获取类的实例
1.4 单例设计模式的实现
单例模式的实现⽅式有多种,包括懒汉式、饿汉式等。
- 饿汉式指的是在类加载时就已经完成了实例的创建,不管后⾯创建的实例有没有使⽤,先创建再说,所以叫做“饿汉”。
- 而懒汉式指的是只有在请求实例时才会创建,如果在⾸次请求时还没有创建,就创建⼀个新的实例,如果已经创建,就返回已有的实例,意思就是需要使⽤了再创建,所以称为“懒汉”。
在多线程环境下,由于饿汉式在程序启动阶段就完成了实例的初始化,因此不存在多个线程同时尝试初始化实例的问题,但是懒汉式中多个线程同时访问 getInstance() ⽅法,并且在同⼀时刻检测到实例没有被创建,就可能会同时创建实例,从⽽导致多个实例被创建,这种情况下我们可以采⽤⼀些同步机制,例如使⽤互斥锁来确保在任何时刻只有⼀个线程能够执⾏实例的创建。
饿汉模式代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include<iostream> using namespace std;
class TaskQueue { public: static TaskQueue* getInstance() { return m_taskQ; }
void print() { cout << "单利对象成员函数" << endl; }
private: TaskQueue() = default; TaskQueue(const TaskQueue& t) = default; TaskQueue& operator = (const TaskQueue& t) = default;
static TaskQueue* m_taskQ; };
TaskQueue* TaskQueue::m_taskQ = new TaskQueue;
int main() {
TaskQueue* taskQ = TaskQueue::getInstance(); taskQ->print(); return 0; }
|

懒汉模式代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include<iostream> #include<mutex> using namespace std;
class TaskQueue { public: static TaskQueue* getInstance() { m_mutex.lock(); if (m_taskQ == nullptr) { m_taskQ = new TaskQueue; } m_mutex.unlock(); return m_taskQ; }
void print() { cout << "单利对象成员函数" << endl; }
private: TaskQueue() = default; TaskQueue(const TaskQueue& t) = default; TaskQueue& operator = (const TaskQueue& t) = default;
static TaskQueue* m_taskQ; static mutex m_mutex; };
TaskQueue* TaskQueue::m_taskQ = nullptr;
int main() {
TaskQueue* taskQ = TaskQueue::getInstance(); taskQ->print(); return 0; }
|

2. 工厂模式
1.工厂模式简介
工厂模式的三种类型:简单工厂模式、工厂方法模式和抽象工厂模式。工厂模式的作用是生产对象,可以简化代码、提高可维护性,并旦可以通过工厂类生产多种对象。简单工厂模式适用于创建简单的对象,工厂模式适用于创建复杂的对象,而抽象工厂模式适用于创建更复杂的对象。
2. 简单工厂模式
简单工厂模式是一种创建型设计模式,旨在通过一个工厂方法来创建对象,而无需直接暴露对象的实例化逻辑。简单工厂模式通常包括一个工厂类和多个产品类。工厂类负责根据客户端的请求,返回对应的产品类实例。
在简单工厂模式中,客户端只需要通过调用工厂类的方法,并传入相应的参数,而无需直接实例化产品类。工厂类根据客户端传入的参数决定创建哪个产品类的实例,并将实例返回给客户端。
简单工厂模式的优点在于,它封装了实例化的细节,使得客户端与具体产品类解耦,增强了灵活性和可维护性。客户端只需要知道需要什么类型的产品,而无需关心具体的实现细节。同时,如果需要新增产品类时,只需修改工厂类即可,不需要修改客户端代码。
然而,简单工厂模式也有一些限制。例如,当需要创建多种类型的产品实例时,工厂类的代码可能会变得复杂,并且随着产品类型的增加,工厂类的责任也会越来越大。因此,在一些复杂的场景下,可能需要使用其他更灵活的创建型设计模式,如工厂方法模式或抽象工厂模式。
总的来说,简单工厂模式提供了一种简单而灵活的方式来创建对象,对于一些简单的对象创建场景是很有用的。
代码示例:
在C++语言中,简单工厂模式可以通过以下方式来实现:
首先,定义一个产品的基类或接口,所有具体产品类都应该实现这个基类或接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Product { public: virtual void operation() = 0; }; class ConcreteProductA : public Product { public: void operation() override { } }; class ConcreteProductB : public Product { public: void operation() override { } };
|

然后,实现一个简单工厂类,该工厂类包含一个静态方法用于创建产品实例。
1 2 3 4 5 6 7 8 9 10 11 12
| class SimpleFactory { public: static Product* createProduct(const std::string& type) { if (type == "A") { return new ConcreteProductA(); } else if (type == "B") { return new ConcreteProductB(); } else { return nullptr; } } };
|

最后,客户端可以通过简单工厂类来创建具体的产品对象。
1 2 3 4 5 6 7 8 9
| int main() { Product* productA = SimpleFactory::createProduct("A"); productA->operation(); Product* productB = SimpleFactory::createProduct("B"); productB->operation(); delete productA; delete productB; return 0; }
|

在上面的示例中,通过调用SimpleFactory::createProduct()
方法并传入不同的类型参数,就可以创建相应类型的产品对象。这样,客户端就可以通过工厂类来创建和使用产品对象,而无需直接处理具体产品类的实例化逻辑。
需要注意的是,简单工厂模式通常是静态方法创建产品对象,但这并不是必须的,你也可以通过实例化工厂类来创建产品对象。另外,如果需要增加新的产品类型,只需要修改工厂类的逻辑即可,而不需要修改客户端代码。
3. 工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但将具体的对象创建过程交给子类来实现。工厂方法模式通过让子类决定实例化哪个具体类来实现对象的创建,从而实现了将对象的创建和使用解耦的目的。
工厂方法模式一般包括以下角色:
- 抽象产品(Product):定义了产品的共同接口,具体的产品类必须实现这个接口。
- 具体产品(ConcreteProduct):实现了抽象产品接口,是工厂方法模式中具体创建的对象。
- 抽象工厂(Factory):定义了一个工厂的接口,包含一个创建产品的抽象方法,具体的工厂类必须实现这个接口。
- 具体工厂(ConcreteFactory):实现了抽象工厂接口,负责实例化具体的产品对象。
工厂方法模式的关键在于通过抽象工厂和具体工厂的组合,将对象的创建过程推迟到子类中实现。客户端通过使用抽象工厂来创建产品对象,而无需关心具体的产品类和实例化细节。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Product { public: virtual void operation() = 0; };
class ConcreteProductA : public Product { public: void operation() override { } };
class ConcreteProductB : public Product { public: void operation() override { } };
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(); } };
|

客户端使用工厂方法模式来创建产品对象:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int main() { Factory* factoryA = new ConcreteFactoryA(); Product* productA = factoryA->createProduct(); productA->operation(); Factory* factoryB = new ConcreteFactoryB(); Product* productB = factoryB->createProduct(); productB->operation(); delete factoryA; delete productA; delete factoryB; delete productB; return 0; }
|

在上述示例中,抽象工厂 Factory 定义了一个用于创建产品对象的抽象方法 createProduct()。具体的工厂类 ConcreteFactoryA 和 ConcreteFactoryB 分别实现了 createProduct() 方法,并通过返回具体的产品对象来实现对象的创建。客户端通过使用抽象工厂 Factory 来创建产品对象,而无需直接关心具体的产品类和实例化细节。
工厂方法模式的优点包括增强了代码的可扩展性和可维护性,将对象的创建和使用解耦,允许在不修改现有代码的情况下引入新的产品和工厂。然而,工厂方法模式也会增加类的个数,导致代码的复杂性增加。在使用工厂方法模式时,需要根据具体情况选择合适的抽象工厂和具体工厂来创建对象。
4. 抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体的类。抽象工厂模式通过将对象的创建和使用解耦,使得客户端代码与具体类的实现分离,从而实现了对象的变化和替换的灵活性。
抽象工厂模式一般包括以下角色:
- 抽象工厂(Abstract Factory):定义了创建一系列产品对象的接口,通常包含多个创建产品的抽象方法。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体的产品对象。
- 抽象产品(Abstract Product):定义了产品的共同接口,具体的产品类必须实现这个接口。
- 具体产品(Concrete Product):实现了抽象产品接口,是抽象工厂模式中具体创建的对象。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| class AbstractProductA { public: virtual void operationA() = 0; };
class ConcreteProductA1 : public AbstractProductA { public: void operationA() override { } };
class ConcreteProductA2 : public AbstractProductA { public: void operationA() override { } };
class AbstractProductB { public: virtual void operationB() = 0; };
class ConcreteProductB1 : public AbstractProductB { public: void operationB() override { } };
class ConcreteProductB2 : public AbstractProductB { public: void operationB() override { } };
class AbstractFactory { public: virtual AbstractProductA* createProductA() = 0; virtual AbstractProductB* createProductB() = 0; };
class ConcreteFactory1 : public AbstractFactory { public: AbstractProductA* createProductA() override { return new ConcreteProductA1(); } AbstractProductB* createProductB() override { return new ConcreteProductB1(); } };
class ConcreteFactory2 : public AbstractFactory { public: AbstractProductA* createProductA() override { return new ConcreteProductA2(); } AbstractProductB* createProductB() override { return new ConcreteProductB2(); } };
|

客户端使用抽象工厂模式来创建一系列产品对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int main() { AbstractFactory* factory1 = new ConcreteFactory1(); AbstractProductA* productA1 = factory1->createProductA(); AbstractProductB* productB1 = factory1->createProductB(); productA1->operationA(); productB1->operationB(); delete factory1; delete productA1; delete productB1; AbstractFactory* factory2 = new ConcreteFactory2(); AbstractProductA* productA2 = factory2->createProductA(); AbstractProductB* productB2 = factory2->createProductB(); productA2->operationA(); productB2->operationB(); delete factory2; delete productA2; delete productB2; return 0; }
|

在上述示例中,抽象工厂 AbstractFactory 定义了创建一系列产品对象的抽象方法 createProductA() 和 createProductB()。具体的工厂类 ConcreteFactory1 和 ConcreteFactory2 分别实现了这两个抽象方法,通过返回具体的产品对象来实现对象的创建。客户端通过使用抽象工厂 AbstractFactory 来创建一系列产品对象,而无需直接关心具体的产品类和实例化细节。
抽象工厂模式可以有效地封装一系列产品的创建过程,使得客户端与具体产品的实现解耦。同时,抽象工厂模式也提供了一种机制,使得一组相关的产品对象可以被一起替换,而无需修改客户端代码。然而,抽象工厂模式的扩展性较差,对于新增加的产品或者产品族会产生较大的修改。在使用抽象工厂模式时,需要根据具体情况选择合适的抽象工厂和具体工厂来创建对象。
3.装饰器模式
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变原有对象结构和功能的基础上,动态地给对象添加额外的职责或功能。
装饰器模式的主要特点包括:
- \1. 保持了被装饰对象的核心职责不变。
- \2. 能够透明地为对象添加新的行为和功能。
- \3. 可以通过多个装饰器的组合来实现复杂的功能扩展。
在实现装饰器模式时,通常会有一个抽象构件(Component)类定义了对象的基本操作接口,具体构件(ConcreteComponent)类实现了这些基本操作,装饰器(Decorator)类继承自抽象构件类并包含一个指向抽象构件对象的引用,具体装饰器(ConcreteDecorator)类在装饰器类的基础上实现了额外的功能。
装饰器模式的优点包括:
- \1. 提供了比继承更灵活的扩展对象功能的方式。
- \2. 可以有效地避免类数量的爆炸式增长。
缺点是:会增加代码的复杂性,在理解和维护上可能会有一定难度。
以下是一个使用 C++ 实现装饰器模式的示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <iostream>
class Component { public: virtual void operation() = 0; };
class ConcreteComponent : public Component { public: void operation() override { std::cout << "执行具体组件的操作" << std::endl; } };
class Decorator : public Component { protected: Component* component;
public: Decorator(Component* comp) : component(comp) {}
void operation() override { if (component) { component->operation(); } } };
class ConcreteDecoratorA : public Decorator { public: ConcreteDecoratorA(Component* comp) : Decorator(comp) {}
void operation() override { std::cout << "在操作前添加额外功能 A" << std::endl; Decorator::operation(); std::cout << "在操作后添加额外功能 A" << std::endl; } };
class ConcreteDecoratorB : public Decorator { public: ConcreteDecoratorB(Component* comp) : Decorator(comp) {}
void operation() override { std::cout << "在操作前添加额外功能 B" << std::endl; Decorator::operation(); std::cout << "在操作后添加额外功能 B" << std::endl; } };
int main() { Component* component = new ConcreteComponent(); Component* decoratorA = new ConcreteDecoratorA(component); Component* decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB->operation();
delete decoratorB; delete decoratorA; delete component;
return 0; }
|

在上述代码中,我们首先定义了一个抽象组件 Component ,然后有一个具体组件 ConcreteComponent 实现了其操作。
Decorator 是装饰器的抽象类,持有一个组件的指针,并在其 operation 方法中调用所持有组件的操作。
ConcreteDecoratorA 和 ConcreteDecoratorB 是具体的装饰器类,它们重写了 operation 方法,在调用被装饰组件的操作前后添加了额外的功能。
在 main 函数中,我们通过层层装饰并调用操作来展示装饰器模式的效果。最后记得释放动态分配的内存。