系列综述:
来源:该系列是主要参考《大话设计模式》和《设计模式(可复用面向对象软件的基础)》,其他详细知识点拷验来自于各大平台大佬的博客。
总结:汇总篇
如果对你有用,希望关注·点赞·收藏一波。
对象创建型模式
简单(静态)工厂模式
- 核心:将对象的创建过程封装在工厂类中,客户端只需要向工厂类提出请求即可,从而达到客户端与具体产品类之间的解耦合。
- 抽象原理
- 抽象产品基类 :定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品子类 :继承抽象产品的子类,实现具体产品
- 静态工厂类 :提供了创建产品的方法,调用者通过该方法来获取产品。
- 代码原理
- 基类:数据成员+虚函数接口(动态基础)
- 派生类:实现虚函数,即实现类的具体功能
- 静态工厂类:使用switch结构根据传入的参数动态new对应子类对象
- 调用:使用基类对象承接静态工厂动态生成对应子类对象赋值给父类
- 特点:
- 破坏开闭原则。拓展产品需要修改原工厂内部的逻辑
- 符合单一职责原则。将对象的
创建逻辑
和实现的业务逻辑
进行了分离
- 示例代码
// 产品基类:纯虚函数接口(抽象的规则)+ 规则操作的数据成员
class Operation
{
public:
//
virtual int GetResult() =0;
public:
double m_Num1;
double m_Num2;
};
// 算法子类1:重新父类虚函数,实现算法
class OperationAdd:Public Operation
{
public:
int GetResult(){
return m_Num1 + m_Num2;
}
};
// 算法子类2:重新父类虚函数,实现算法
class OperationSub:Public Operation
{
public:
int GetResult(){
return m_Num1 - m_Num2;
}
};
// 静态工厂类:根据对象实例化
class OperationFactry
{
public:
OperationFactry(void);
~OperationFactry(void);
// static主要功能是无需创建类,就可以调用方法
static Operation CreateOperate(char c )
{
switch(c)
{
case '+':
return new OperationAdd;
break;
case '-':
return new OperationSub;
break;
}
}
};
// 调用
Operation oper;// 父类对象
oper = OperationFactry::CreateOperate("+");// 核心:具体的子类转换成父类,进行虚函数的动态调用
oper.m_Num1 = 1;// 给父类对象的数据成员进行赋值
oper.m_Num2 = 2;
double result = oper.GetResult();
工厂方法模式
- 抽象原理
- 抽象产品基类 :定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品子类 :实现或者继承抽象产品的子类
- 工厂基类 :定义类别区分的功能接口
- 具体工厂子类:具体工厂对应生产具体的产品
- 代码原理:
- 定义一个用于创建对象的接口,让子类决定实例化哪一个类
- 使用抽象解除对于具体实例的耦合,将简单工厂模式中
工厂类的分支
导致的与对象创建的耦合
使用抽象类进行解决
- 特点
- 符合单一职责原则和开闭原则
- 增加系统复杂度和开销,并且大量产品会导致对应工厂类的膨胀
- 实现方法
// 产品类与简单工厂方法相同,工厂方法就是将工厂抽象出来,具体对象由具体对象创建 ··· // 工厂方法接口类:根据对象实例化 class IFactory{ virtual Operation* CreateOperate() = 0; } // 工厂子类 class OperationAddFactory : public IFactory{ public: Operation CreateOperate(){ return new OperationAdd(); } } class OperationSubFactory : IFactory{ public: Operation* CreateOperate(){ return new OperationSub(); } } // 调用 IFactory *factory = new OperationXXXFactory();// 子转父:具体工厂赋值给抽象工厂 Operation *oper = factory.CreateOperate();// 子转父:具化的抽象工厂生产具体产品赋值给抽象产品 oper.m_Num1 = 1;// 给父类对象的数据成员进行赋值 oper.m_Num2 = 2; double result = oper.GetResult();
抽象工厂模式
- 抽象原理
- 抽象工厂基类:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。
- 具体工厂类:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
多个
抽象产品基类:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。对应的
具体产品类:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。
- 特点
- 满足开闭原则:当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码。
- 不满足开闭原则:当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改。
- 当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。
- 代码示例
// 抽象操作类 class Operation { public: virtual double getResult(double num1, double num2) = 0; }; // 加法操作类 class AddOperation : public Operation { public: double getResult(double num1, double num2) { return num1 + num2; } }; // 减法操作类 class SubOperation : public Operation { public: double getResult(double num1, double num2) { return num1 - num2; } }; // 乘法操作类 class MulOperation : public Operation { public: double getResult(double num1, double num2) { return num1 * num2; } }; // 除法操作类 class DivOperation : public Operation { public: double getResult(double num1, double num2) { if (num2 == 0) { throw "除数不能为0"; } return num1 / num2; } }; // 抽象工厂类:具有所有的工厂实现接口 class Factory { public: virtual Operation* createAdd() = 0; virtual Operation* createSub() = 0; virtual Operation* createMul() = 0; virtual Operation* createDiv() = 0; }; // 加减工厂类 class AddSubFactory : public Factory { public: Operation* createAdd() { return new AddOperation(); } Operation* createSub() { return new SubOperation(); } Operation* createMul() { return nullptr; } Operation* createDiv() { return nullptr; } }; // 乘除工厂类 class MulDivFactory : public Factory { public: Operation* createAdd() { return nullptr; } Operation* createSub() { return nullptr; } Operation* createMul() { return new MulOperation(); } Operation* createDiv() { return new DivOperation(); } }; // 调用 Factory* factory = new AddSubFactory(); // 创建加减工厂实例 // 创建加法操作实例并进行计算 Operation* add = factory->createAdd(); double result1 = add->getResult(1, 2); cout << "1 + 2 = " << result1 << endl; // 创建减法操作实例并进行计算 Operation* sub = factory->createSub(); double result2 = sub->getResult(4, 2); cout << "4 - 2 = " << result2 << endl; // 释放资源 delete add; delete sub; delete factory;
单例模式
- 定义:保证一个类只能产生一个实例,并提供一个访问它的全局访问点。
- 私有化的构造函数,保证类外无法实例化
- 私有化静态的类对象,保证类只有一个实例
- 公开静态的成员函数,作为类的全局访问点
- 特点
- 优点:单例类对象具有唯一性,减少了内存的开销,尤其是频繁的创建和销毁实例。
- 缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
- 类型
- 懒汉式:适合
单线程
且单例对象不经常使用
的情况- 单线程:在多线程下,不是线程安全的,同步锁会影响性能。
- 不经常使用:单例类的实例的初始化会延迟lazy到第一次被引用时候,可以避免资源浪费
#include <iostream> #include <mutex> // 互斥锁头文件 using namespace std; class SinglePattern { public: // 1. 公共实例化接口:返回对象指针来保证对象的唯一性 static SinglePattern *GetInstance() { // 2. 线程安全:lock_guard会在构造函数中加锁, // 在析构函数中自动解锁 lock_guard<mutex> lock(mtx); // 3. 延迟绑定:类的实例化延迟到第一次使用时候 if (instance == nullptr) { instace = new SinglePattern(); } return instance; } private: static SinglePattern *instance; static mutex mtx; SinglePattern(const SinglePattern &single) = delete; SinglePattern& operator=(const SinglePattern&) = delete; SinglePattern() {} }; // 类内静态变量需要紧跟在类外进行初始化操作 SinglePattern* SinglePattern::instance = nullptr; mutex SinglePattern::mtx; int main() { Singleton* s1 = Singleton::getInstance(); return 0; }
- 饿汉式:适用于
多线程
且单例对象经常使用
的情况。- 线程安全:无需担心多线程下的执行乱序问题
- 经常使用:单例对象在未使用时,就被初始化
class SinglePattern { public: // 1. 公共实例化接口:通过返回对象的引用避免拷贝构造 static SinglePattern& GetInstance() { // 2. 线程安全的保证:静态局部变量只会被原子的初始化一次 static SinglePattern instance; return instance; } private: // 3. 保证实例的唯一性:禁止默认构造、拷贝构造和拷贝赋值 SinglePattern(); SinglePattern(const SinglePattern &single) = delete; SinglePattern& operator=(const SinglePattern&) = delete; // delete相比private可以避免友元函数和成员函数的访问 } int main() { // 获取单例对象的引用 SinglePattern& single_instance = SinglePattern::GetInstance(); }
- 懒汉式:适合
Builder建造者/生成器模式
- 核心:
- 执行函数流相同,但是执行函数的参 数不同,使得
同样的构建
过程可以创建不同的表示
- 将一个复杂对象的
构建
与表示
分离,使得同样的构建过程
可以创建不同的表示
。 - 适合场景:当一个类的构造函数参数超过4个,而且这些参数有些是可选的时
- 执行函数流相同,但是执行函数的参 数不同,使得
- 抽象原理
- 产品(Product):描述产品,包括
产品的属性
和对应的set函数
- 抽象建造者基类(Builder):描述建造流程,主要包含
私有的建造对象
、建造对象流程的纯虚函数
、返回建造对象函数
- 具体建造者类(ConreteBuilder):具体化对象的各个组成部分的创建,包含
产品属性set的虚函数
- 导演类(Director):负责指导建造过程,包含
返回建造对象的函数
,其中是抽象建造流程
- 产品(Product):描述产品,包括
- 优点
- S符合单一职责原则:隔离复杂对象的创建和表示,可以对复杂对象的创建过程进行更精细的控制。
- O符合开放封闭原则
- 对拓展开放:建造者模式将对象的构建过程分步进行,增加新的建造者不会影响现有的系统结构。
- 对修改封闭:通过具体建造类可以隐藏复杂对象的创建细节
- 缺点
- 增加了系统中类和对象的个数,可能会增加系统的复杂度和理解难度。
- 适用于构建复杂对象,如果构建简单对象会增加系统复杂度
- 示例代码
// 产品描述 class Product{ public: void setMainBoard(const string& main_Board) { main_Board_= main_Board; } void setRAM(const string& cpu) { cpu_= cpu; } void setCPU(const string& ram) { ram_= ram; } private: string main_Board_; string cpu_; string ram_; }; // 抽象建造者 class Builder{ public: // 建造流程 virtual void AddMainBoard() = 0;// 装配主板 virtual void AddCpu() = 0; // 装配CPU virtual void AddGpu() = 0; // 装配GPU // 返回建造对象 Product getComputer() { return m_computer; } protected: Product computer_; // 电脑产品 }; // 坠机堡垒华硕电脑 建造者 class ASUABuilder : public Builder{ public: // 装配主板 virtual void AddMainBoard() { m_computer.setMainBoard("B760"); } // 装配cpu virtual void AddCpu() { m_computer.setCPU("Intel 酷睿i7-8700K"); } // 装配内存 virtual void AddRAM() { m_computer.setRAM("三星DDR4 2666mhz 16G"); } }; // 人傻钱多戴尔电脑 建造者 class HPBuilder : public Builder{ public: // 装配主板 virtual void AddMainBoard() { m_computer.setMainBoard("B760"); } // 装配cpu virtual void AddCpu() { m_computer.setCPU("Intel 酷睿i7-8750h"); } // 装配内存 virtual void AddRAM() { m_computer.setRAM("海力士DDR4 2666mhz 8G"); } }; // 导演类(负责指导建造过程) class Director{ public: Product build(Builder& builder){ builder.AddMainBoard(); builder.AddCPU(); builder.AddRAM(); return builder.getComputer(); } }; // 使用示例 int main(){ ASUABuilder asus_builder; HPBuilder hp_builder; Director director; Product asus_computer = director.build(asus_builder); Product hp_computer = director.build(hp_builder); return 0; }