当前位置: 首页 > news >正文

在C++中,工厂模式的思考(《C++20设计模式》及常规设计模式对比)

文章目录

  • 一、前言
  • 二、讲解
    • 1、构造函数的弊端
    • 2、工厂方法(解决上述弊端)
    • 3、简单工厂
      • 3.1 **UML类图**
      • 3.2 **实现**
    • 4、工厂模式
      • 4.1 **UML类图**
      • 4.2 **实现**
    • 5、抽象工厂
      • 5.1 **UML类图**
      • 5.2 **实现**
  • 三、总结

一、前言

在看《C++20设计模式》一书中产生了疑惑,就是经典工厂模式与这一书中的讲解差别很大,在此分享我心中的疑惑。

  • 讲解的方式不一样
    • 经典工厂模式分为三类 —— 简单工厂、工厂模式、抽象工厂。
    • 《C++20设计模式》一书是这么讲解的 —— 工厂方法、工厂、抽象工厂

这里说一下,其实他们两个讲解的东西都是同一个东西,只不过讲解的侧重点不同,而且《C++20设计模式》讲的东西还少了工厂模式的讲解。如果你仔细看书中的例子就会发现,这里《C++20设计模式》中的工厂指的是经典工厂中的简单工厂。

  • 如何统一经典的工厂模式和《C++20设计模式》一书中的工厂模式。

    • 他们对于为什么要有工厂模式的目的不同,也其实就是讲解方式的不同。

      • 经典工厂模式的目的: 使得创建对象的过程与使用对象的过程分离,高代码的可维护性和可扩展性。
      • 《C++20设计模式》工厂模式: 普通构造函数没法对参数进行验证,所以使用工厂模式。

下面是笔者认为,应该正确的讲解方式,可以统一 经典工厂模式的讲解和《C++20设计模式》中的工厂模式的讲解。

相关代码可以在这里,如有帮助给个star!AidenYuanDev/design_patterns_in_modern_Cpp_20

二、讲解

1、构造函数的弊端

无法对要进行创建的对象的参数进行验证
比如说救生员对象要求是八块腹肌,你却创建了六块腹肌,也即是一个不符合要求的对象,我们正常的需求肯定是不创建这个对象,或者创建一个空对像,因为它不符合要求嘛!但是构造函数却做不到这一点!

因为,构造函数不能返回任意的数据类型,

2、工厂方法(解决上述弊端)

用静态成员方法,来代替构造函数
很自然的想法嘛,既然构造函数没有返回值,那么我们就用成员函数嘛!成员函数不是有返回值嘛,那么就可以进行参数验证啦!

使用静态成员函数,是为了在创建对象之前就可以调用这个方法(因为这个方法就是为了创建对象,肯定要在创建对象之前就能调用嘛!所以用静态!

实现

#include <iostream>
#include <memory>
using namespace std;class Product_Base {
protected:int a;int b;Product_Base(int a, int b) : a(a), b(b) {}
};class Product : public Product_Base {int c;protected:Product(int a, int b, int c) : Product_Base(a, b), c(c) {}public:static unique_ptr<Product> new_product(int a, int b, int c) {if (a < 0) return nullptr;return unique_ptr<Product>(new Product(a, b, c));}void show() { cout << a << '\t' << b << '\t' << c << endl; }
};int main() {unique_ptr<Product> p1 = Product::new_product(4, 5, 6);p1->show();return 0;
}

3、简单工厂

现在就是经典工厂模式的内容了,上面的代码看似已经可以很好的解决问题了,为什么还要有简单工厂呢?

  1. 使得创建对象的过程与使用对象的过程分离,提高代码的可维护性和可扩展性。(常见的答案)
  2. 工厂可以根据需要动态创建不同类型的对象,而不需要客户端了解具体的创建逻辑。
  3. 可以在工厂中判断对象与对象之间的关系。

3.1 UML类图

请添加图片描述

3.2 实现

#include <iostream>
#include <memory>
using namespace std;class Product_Base{
protected:int a;int b;Product_Base(int a, int b) : a(a), b(b){}
public:virtual void show() = 0;
};class Product_A : public Product_Base {int c;Product_A(int a, int b, int c) : Product_Base(a, b), c(c) {}
public:void show(){cout << a << '\t' << b << '\t' << c << endl;}static unique_ptr<Product_A> create(int a, int b, int c) {return unique_ptr<Product_A>(new Product_A(a, b, c));}
};class Product_B : public Product_Base {int c;Product_B(int a, int b, int c) : Product_Base(a, b), c(c) {}public:void show(){cout << a << '\t' << b << '\t' << c << endl;}static unique_ptr<Product_B> create(int a, int b, int c) {return unique_ptr<Product_B>(new Product_B(a, b, c));}};class Product_C : public Product_Base {int c;Product_C(int a, int b, int c) : Product_Base(a, b), c(c) {}friend class Simple_Factor;
public:void show(){cout << a << '\t' << b << '\t' << c << endl;}static unique_ptr<Product_C> create(int a, int b, int c) {return unique_ptr<Product_C>(new Product_C(a, b, c));}};enum class Product_Type {A,B,C
};class Simple_Factor{
public:static unique_ptr<Product_Base> creater_producter(Product_Type type, int a, int b, int c) {switch (type) {case Product_Type::A:if (a < 0) return nullptr;return Product_A::create(a, b, c); case Product_Type::B:if (b < 0) return nullptr;return Product_B::create(a, b, c);case Product_Type::C:if (c < 0) return nullptr;return Product_C::create(a, b, c);}return nullptr;}
};int main() { unique_ptr<Product_Base> p = Simple_Factor::creater_producter(Product_Type::A, 4, 5, 6);p->show();return 0; 
}

4、工厂模式

上面的简单工厂模式的缺点是当新增产品的时候就要去修改工厂的类,这就违反了开放封闭原则(对扩展开发,对修改关闭)于是,就出现了工厂方法模式,也就是工厂模式。

工厂抽象,有新的产品直接创建新的工厂就可以

4.1 UML类图

请添加图片描述

4.2 实现

#include <iostream>
#include <memory>
using namespace std;class Product_Base{
protected:int a;int b;Product_Base(int a, int b) : a(a), b(b){}
public:virtual void show() = 0;
};class Product_A : public Product_Base {int c;Product_A(int a, int b, int c) : Product_Base(a, b), c(c) {}
public:void show(){cout << a << '\t' << b << '\t' << c << endl;}static unique_ptr<Product_A> create(int a, int b, int c) {return unique_ptr<Product_A>(new Product_A(a, b, c));}
};class Product_B : public Product_Base {int c;Product_B(int a, int b, int c) : Product_Base(a, b), c(c) {}public:void show(){cout << a << '\t' << b << '\t' << c << endl;}static unique_ptr<Product_B> create(int a, int b, int c) {return unique_ptr<Product_B>(new Product_B(a, b, c));}};class Product_C : public Product_Base {int c;Product_C(int a, int b, int c) : Product_Base(a, b), c(c) {}friend class Simple_Factor;
public:void show(){cout << a << '\t' << b << '\t' << c << endl;}static unique_ptr<Product_C> create(int a, int b, int c) {return unique_ptr<Product_C>(new Product_C(a, b, c));}};enum class Product_Type {A,B,C
};class Factor_Base{
public:virtual unique_ptr<Product_Base> new_product(int a, int b, int c) = 0;
};class Factor_A : public Factor_Base {
public:unique_ptr<Product_Base> new_product(int a, int b, int c) {if (a < 0) return nullptr;return Product_A::create(a, b, c);}
};class Factor_B : public Factor_Base {
public:unique_ptr<Product_Base> new_product(int a, int b, int c) {if (b < 0) return nullptr;return Product_B::create(a, b, c);}
};int main() { unique_ptr<Factor_Base> factor_a = make_unique<Factor_A>();unique_ptr<Product_Base> product_a = factor_a->new_product(1, 5, 7);product_a->show();return 0; 
}

5、抽象工厂

这个模式比普通的工厂模式抽象一点。可以做到一个工厂生产多个产品,比如苹果工厂可以生产苹果也就是生产苹果汁。

N个产品M个工厂。总结:工厂可以灵活的生产商品。

5.1 UML类图

请添加图片描述

5.2 实现

#include <iostream>
#include <memory>
using namespace std;class Product_Base {
protected:int a;int b;Product_Base(int a, int b) : a(a), b(b) {}public:virtual void show() = 0;
};class Product_A : public Product_Base {int c;Product_A(int a, int b, int c) : Product_Base(a, b), c(c) {}public:void show() { cout << a << '\t' << b << '\t' << c << endl; }static unique_ptr<Product_A> create(int a, int b, int c) { return unique_ptr<Product_A>(new Product_A(a, b, c)); }
};class Product_B : public Product_Base {int c;Product_B(int a, int b, int c) : Product_Base(a, b), c(c) {}public:void show() { cout << a << '\t' << b << '\t' << c << endl; }static unique_ptr<Product_B> create(int a, int b, int c) { return unique_ptr<Product_B>(new Product_B(a, b, c)); }
};class Product_C : public Product_Base {int c;Product_C(int a, int b, int c) : Product_Base(a, b), c(c) {}friend class Simple_Factor;public:void show() { cout << a << '\t' << b << '\t' << c << endl; }static unique_ptr<Product_C> create(int a, int b, int c) { return unique_ptr<Product_C>(new Product_C(a, b, c)); }
};enum class Product_Type { A, B, C };class Factor_Base {
public:virtual unique_ptr<Product_Base> new_product1(int a, int b, int c) = 0;virtual unique_ptr<Product_Base> new_product2(int a, int b, int c) = 0;
};class Factor_A : public Factor_Base {
public:unique_ptr<Product_Base> new_product1(int a, int b, int c) {if (a < 0) return nullptr;return Product_A::create(a, b, c);}unique_ptr<Product_Base> new_product2(int a, int b, int c) {if (a < 0) return nullptr;return Product_B::create(a, b, c);}
};class Factor_B : public Factor_Base {
public:unique_ptr<Product_Base> new_product1(int a, int b, int c) {if (b < 0) return nullptr;return Product_B::create(a, b, c);}
};int main() {unique_ptr<Factor_Base> factor_a = make_unique<Factor_A>();unique_ptr<Product_Base> product_2 = factor_a->new_product2(1, 5, 7);product_2->show();return 0;
}

三、总结

工厂模式的优点:

  1. 使得创建对象的过程与使用对象的过程分离,高代码的可维护性和可扩展性。
  2. 使用工厂模式可以对参数进行验证。

最后如果有帮助,麻烦点个赞吧!!!

相关文章:

  • Word中输入文字时,后面的文字消失
  • 如何在OpenEuler 上快速部署一套Zabbix7.0监控系统
  • 性能测试方法与工具比较
  • 云计算 | 期末梳理(上)
  • 零知识证明技术:隐私保护的利器
  • 【原创教程】一次搞定伺服原点问题(进阶篇)
  • 【图片知识】现在各种平台为什么开始使用 webp格式的图片 而不是传统的jpg或者png
  • python 笔试面试八股(自用版~)
  • git基本使用(二):git分支的操作命令
  • 【PYG】Cora数据集分析argmax(dim=1)输出
  • 初学51单片机之简易电子密码锁及PWM应用扩展
  • 二维码登录的原理
  • vue根据文字长短展示跑马灯效果
  • Kafka-服务端-副本同步-源码流程
  • 编程入门:从零开始学习编程的方法与步骤
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • 0x05 Python数据分析,Anaconda八斩刀
  • bearychat的java client
  • CSS 提示工具(Tooltip)
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • Java读取Properties文件的六种方法
  • k个最大的数及变种小结
  • Leetcode 27 Remove Element
  • Linux各目录及每个目录的详细介绍
  • Node + FFmpeg 实现Canvas动画导出视频
  • Sass Day-01
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 回顾 Swift 多平台移植进度 #2
  • 技术发展面试
  • 区块链技术特点之去中心化特性
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 数组的操作
  • 我这样减少了26.5M Java内存!
  • 一文看透浏览器架构
  • 做一名精致的JavaScripter 01:JavaScript简介
  • postgresql行列转换函数
  • ​configparser --- 配置文件解析器​
  • # 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)php新闻发布平台 毕业设计 141646
  • (四)linux文件内容查看
  • (转)拼包函数及网络封包的异常处理(含代码)
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .NET 5种线程安全集合
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .net core Swagger 过滤部分Api
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .Net 基于MiniExcel的导入功能接口示例
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET文档生成工具ADB使用图文教程
  • /etc/sudoer文件配置简析
  • @angular/cli项目构建--http(2)
  • @Autowired 与@Resource的区别