设计模式学习[13]---抽象工厂模式+简单工厂+工厂方法模式回顾

devtools/2024/12/27 10:08:26/

文章目录

  • 前言
    • 1.原理阐述
      • 1.1 说明1
      • 1.2 说明2
    • 2.举例
  • 总结

前言

之前写过一些工厂的相关内容,详情见这两篇:简单工厂与工厂方法

这篇博客主要讲抽象工厂模式

1.原理阐述

1.1 说明1

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

直接看概念其实还是有点懵的,这里翻译一下。
用一个抽象的类,这个类叫做抽象工厂,去封装一系列相互依赖的实例化的过程。这个实例化涉及到互相依赖的接口,比如A里面包含了abc类型,B里面也包含了abc类型,创建a类型,其实需要依赖它是A还是B这种类型。这样讲可能还是不懂。


1.2 说明2

所以我又结合了另一本设计模式的书看,下面是另一种说法(例子来自于另一本书)。

如果一个工厂子类能够生产不止一种具有相同规格规则的怪物对象,那么就可以有效地减少所创建的工厂子类数量,这就是抽象工厂模式的核心思想

这里怪物对象的例子如下:
假如现在有三种怪物,亡灵类,元素类和机械类;还有三种战斗场地:沼泽地区、山脉地区、城镇。
那么这样的情况,整个游戏其实有9类怪物,分别是沼泽地区的三类怪物,山脉地区的三类怪物、城镇地区的三类怪物。
这样划分的是因为,每个区域的同类型怪物能力差距很大,比如沼泽里面的亡灵类怪物攻击力比城镇的亡灵类怪物攻击力高,这其实就是打游戏的时候的一个环境加成吧。

这时候需要提及了两个概念。产品等级结构产品族
将刚才提到的9种怪物放到一个坐标轴中,我们会发现,按照行的方式来看,每个怪物的种类不同,但是都位于相同场景;如果按照列的方式来看,怪物的种类都相同,但是位于不同场景。

所以如果用一个工厂子类生产一个产品族(1行),那么因为有3个产品族,所以只需要3个工厂可以生产9个产品。

说到最后,就是通过抽象工厂模式,把一个复杂的多种情况的对象,用一个简单的类别工厂作分割。对于上面的例子,把3×3的矩阵变成3个1*3的矩阵。这样每个1×3的矩阵就是一个小的工厂。回到最外层,整个创建实例的最外层的那个接口,就是抽象工厂模式的一种体现。

是不是还是晕?是的,我写到这里,感觉还没能够用非常通俗的语言说明。
我们再来看例子。

2.举例

场景:怪兽有三种类型,亡灵类、元素类、机械类。

需求:我现在要创建不同类型的怪兽对象

基本做法:创建一个怪兽类,怪兽有个属性type表示他是什么类型,要创建哪种对象就根据type类型创建具体的怪兽类,这时候用户需要知道有哪些对象,同时如果还想再加怪兽种类的话,需要在Monster类中进行拓展,类似于switch分支。每加一个类型的怪兽,就需要修改Monster类中创建子类的switch分支。

简单工厂做法:
基本做法中,这种不断修改switch分支的方式,违反了开闭原则,在软件设计中是不合理的。接下来用简单工厂模式进行优化。
我们通过创建一个MonsterFactory工厂,把根据类型实例化过程交给这个工厂类去做,那么对于Monster类来说,它是保持封闭的。如果新增加一个特殊的怪兽类,只需要让这个特殊怪兽类去继承Monster类即可,修改是在这个MonsterFactory这个抽象类中。
下面是简单工厂类图。
在这里插入图片描述

工厂方法模式:
上面这个类图中,我们其实是把这个对类的修改从Monster类移到了MonsterFactory中,但实际上对于MonsterFactory类来说,他也不满足开闭原则,因为我们要一直改这个MonsterFactory类中的switch分支来创建对象。

那么如果我们把这个switch分支用类的方式进行脱离呢?那就是工厂方法模式了。

我们对每一个特定类型的怪兽用一个工厂类去实例化,比如对于亡灵类M_Undead,我们用M_UndeadFactory工厂类去实例化它,其他的几个类也一样。
这样我们可以根据类型string字段type,去创建对应的工厂类,再具体的去调用工厂类的createMonster()函数,从而完成具体实例的创建

在这里插入图片描述

抽象工厂模式
对于我们一开始提及的需求我现在要创建不同类型的怪兽对象,那如果新增一个环境条件呢?就是我们在说明2里面提到的,沼泽,城镇,山脉地形。
那如果按照我们工厂方法模式,是不是得要创建类似于下面9个工厂类:

沼泽亡灵族工厂类
沼泽元素族工厂类
沼泽机械族工厂类
山脉亡灵族工厂类
山脉元素族工厂类
山脉机械族工厂类
城镇亡灵族工厂类
城镇元素族工厂类
城镇机械族工厂类

类图的话就是类似下面红框,不断的去继承这个M_ParFactory

在这里插入图片描述

这似乎工厂太多了吧?所以我们再回到说明2来看,引入产品等级结构产品族

这时候我们再把UML类图画一下,如下图所示。

在这里插入图片描述

这个类图中,我们创建沼泽、山脉、城镇类型的怪兽生成工厂,让一个工厂子类能够生产不止一种具有相同规格规则的怪物对象,那么就可以有效地减少所创建的工厂子类数量。

那么具体main函数的代码体现如下:

//这里省略各种类的说明,具体参考UML类图M_ParFactory* p_mou_fy=new M_Factory_Mountain();//多态工厂,山脉地区的工厂
Monster* pM1=p_mou_fy->createMonster_Element();//创建山脉地区的元素类怪物M_ParFactory* p_twn_fy=new M_Factory_Town();//多态工厂,城镇的工厂
Monster* pM2=p_twn_fy->createMonster_Undead();//创建城镇的亡灵类怪物
Monster* pM3=p_twn_fy->createMonster_Mechanic();//创建城镇的机械类怪物

在main代码中,我们把所有的怪物的创建通过一个M_ParFactory工厂指针去创建,需要什么地区的就new一个什么地区的对象,需要什么类型的怪物,就用Monster*指针去指向。
我们实际对外暴露,并给用户去使用的类实际上就是一个创建怪物的工厂指针,还有一个怪物类的指针。

写到这,应该能明白抽象工厂的意义了。减少工厂方法模式的工厂数量,减少对外暴露的接口,把细节的东西全部封装到一个接口里面。同时要满足开闭原则。

总结

工厂这个大模式的意义最主要还是在于做到软件开发过程中的开闭原则,三种工厂一般作用 的范围不太一样,下面说一下三者的区分和总结。

从代码复杂度上:简单工厂模式最简单,工厂方法次之,抽象工厂模式最复杂。把简单工厂模式中的代码修改得符合开闭原则,就变成了工厂方法模式,修改工厂方法模式的代码使得一个工厂支持对多个具体产品的生产,就变成了抽象工厂模式
从需要的工厂数量上:简单工厂模式需要的工厂数量最少,工厂方法模式需要的工厂数量最多,抽象工厂模式能够有效地减少工厂方法模式所需要的工厂数量(可以将工厂方法模式看做抽象工厂模式的一种特例——抽象工厂模式中的工作若只创建一种对象就是工厂方法模式)
从实际应用上:当项目中的产品数量比较少时考虑使用简单工厂模式,如果项目稍大一点或者为了满足开闭原则,则可以使用工厂方法模式,而对于大型项目中有众多厂商并且每个厂商都生产一系列产品时应该考虑使用抽象工厂模式


http://www.ppmy.cn/devtools/144037.html

相关文章

MongoDB常见面试题总结(上)

MongoDB 基础 MongoDB 是什么? MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常流行的 文档类型数据库 。 …

性能测试度量指标学习笔记

目录 一、概要 二、不同系统软件性能测试度量指标 三、性能测试度量指标 1、响应时间 2、用户数 3、系统处理能力 4、错误率 5、成功率 6、资源占用率 7、CPU利用率 8、内存页交换速率 9、内存占用率 10、磁盘IO 11、磁盘吞吐量 12、网络吞吐量 13、系统稳定性…

网络安全核心目标CIA

网络安全的核心目标是为关键资产提供机密性(Confidentiality)、可用性(Availablity)、完整性(Integrity)。作为安全基础架构中的主要的安全目标和宗旨,机密性、可用性、完整性频频出现,被简称为CIA,也被成为你AIC,只是顺序不同而已…

Flutter组件————BottomNavigationBar

BottomNavigationBar 是Flutter中用于在屏幕底部显示导航栏的组件,它允许用户在几个主要视图之间进行切换。 参数 参数名类型描述itemsList定义导航栏中的每个项目,通常包含图标和标签。onTapValueChanged当用户点击导航栏中的项目时触发的回调函数&am…

Hyperledger Fabric 2.x 环境搭建

Hyperledger Fabric 是一个开源的企业级许可分布式账本技术(Distributed Ledger Technology,DLT)平台,专为在企业环境中使用而设计,与其他流行的分布式账本或区块链平台相比,它有一些主要的区别。 环境准备…

开放词汇目标检测(Open-Vocabulary Object Detection, OVOD)综述

定义 开放词汇目标检测(Open-Vocabulary Object Detection, OVOD)是一种目标检测任务,旨在检测和识别那些未在训练集中明确标注的物体类别。传统的目标检测模型通常只能识别有限数量的预定义类别,而OVOD模型则具有识别“开放词汇…

C++的interface与抽象类

提示:文章 文章目录 前言一、背景二、C的interface与抽象类c 有interface关键词吗?c抽象类有abstract关键词吗?所以c抽象类和abstract没有关系。那什么是抽象类?题目1题目2什么是抽象函数?抽象函数和纯虚函数的区别&am…

单点登录平台Casdoor搭建与使用,集成gitlab同步创建删除账号

一,简介 一般来说,公司有很多系统使用,为了实现统一的用户名管理和登录所有系统(如 GitLab、Harbor 等),并在员工离职时只需删除一个主账号即可实现权限清除,可以采用 单点登录 (SSO) 和 集中式…