系统架构技能之设计模式-抽象工厂模式
一、上篇回顾
上篇我们主要讲述了简单工厂模式和工厂模式。并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下:
简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建。
工厂模式:多个工厂负责多个类型对象的创建,每个工厂只负责具体类型对象的创建,支持无缝的新增类型对象的创建,需要实现工厂接口类和具体的类型对象类。
我们来简单的对比下这2个模式的优缺点:
模式名称 优点 缺点 简单工厂模式 一个工厂负责所有对象的创建,简单灵活 不符合高内聚的原则,不支持无缝的扩展 工厂模式 可以无缝的新增类型,每个工厂职责单一,符合高内聚的原则 工厂类太多,难以维护。
工厂模式,很优雅的解决了应用程序使用对象时的无限new()的操作,同时降低了系统应用之间的耦合性,提高了系统的可维护性和适应性。
二、摘要
本文主要是针对创建型模式中的抽象工厂模式进行讲述,抽象工厂模式是在简单工厂模式的基础上扩展而成的新模式,将简单工厂中的对象的创建过程进行了很优雅的动态配置来完成无
缝的扩展,当然通过一些扩展,可以构建出可支持动态新增或者删除对象的抽象工厂模式。本文将会给出具体的实现方案,相比工厂模式,抽象工厂模式是一个工厂负责多个对象的创建,返回
的具体的类型是这个对象的抽象类型。这样,在客户端引用的时候只需要使用这个工厂返回的对象类型,抽象工厂会自动根据对象的类型动态的创建这个类型对象的实例。大体的过程如下:
上面的图片呢,主要是针对经典的抽象工厂模式给出了一个实现草图的模拟,而我们在实际的项目中可能并不希望给出这么多的抽象工厂工厂实现,我只想给出一个通用的抽象
工厂实现,通过静态方法直接调用,返回我想要的对象类型的实例,而且这个对象类型是可以动态配置的,那么我们如何做到呢?这就是本篇需要讨论的实现方案。本篇将会从
以下几点进行讲述抽象工厂模式:
1、抽象工厂模式的简单实例代码-这里给出的是经典的抽象工厂模式实例代码。我们从经典的实例代码中可以看出这个工厂模式的一些缺点。
2、根据经典工厂模式的缺点,我们给出改进的方案,进一步给出项目中可以使用的通用方案实现。
3、给出上篇中的通过委托来实现的工厂模式方案。
4、通过特性+反射的形式来动态的创建对象。
三、本文大纲
a、上篇回顾。
b、摘要。
c、本文大纲。
d、抽象工厂模式的特点及使用场景。
e、抽象工厂模式的实现方案。
f、抽象工厂模式使用总结。
g、系列进度。
h、下篇预告。
四、抽象工厂模式的特点及使用场景
抽象工厂可以说是三类工厂模式中使用最广泛的,也是最受大家喜爱的模式之一,因为抽象工厂模式解决了一系列相互依赖的对象或者有组合关系的对象的创建过程。举个简单的例子来
说,我们以电脑的显卡和风扇来说吧,我们知道显卡一般在玩游戏的时候,由于渲染图形会产生大量的热量,如果没有好的风扇那么可能无法达到好的散热的效果,这个时候我们可以把显卡和
风扇的创建放在一个抽象工厂中进行创建,因为这2个对象是具有依赖关系的对象,那么我们来给出这个例子的完整实例代码:
先看看2个对象类型的接口和抽象工厂的接口定义
///
/// 定义显卡抽象对象接口
///
public interface IDisplayCard
{
}///
/// 定义显卡风扇抽象对象接口
///
public interface IDisplayFan
{
}///
/// 定义显卡设备抽象工厂接口
///
public interface IAbstractDriveFactory
{
IDisplayCard CreateDisplayCard();IDisplayFan CreateDisplayFan();
}
我们来看看具体类型的实现和抽象工厂的具体实现。
///
/// 定义华硕显卡的具体对象
///
public class DisplayCardAsus : IDisplayCard
{
}
///
/// 华硕显卡配套风扇
///
public class DisplayFanAsus : IDisplayFan
{
}
///
/// 华硕显卡具体实现工厂
///
public class DriveFactoryAsus : IAbstractDriveFactory
{
IDisplayCard CreateDisplayCardAsus()
{
return new DisplayCardAsus();
}IDisplayFan CreateDisplayFanAsus()
{
return new DisplayFanAsus();
}
}
通过上面的代码,我们给出了抽象工厂的一个经典实例的实现方案,当然这不是我们开发中使用的实际形式,那么实际我们在项目中如何使用这个抽象工厂模式呢?我们一般是改进的方
案去使用这个抽象工厂模式,我们如何改进呢?对于目前的,如果我不光创建显卡设备和配套的风扇设备,我还想创建其他的类型的东西,这时候可能我们定义的抽象工厂就无法满足具有相互
依赖或者组合关系的对象类型实例的创建工作了,那么我们如何改进呢,这就是下面要讲述的几类方案。
五、抽象工厂模式的实现方案
5.1、通过配置文件来实现
- 我们先给出基于上面的经典抽象工厂的一个改进的方案,可以支持动态配置的抽象工厂,一个工厂负责动态的创建一些列的可动态配置的对象列表,我们如何做呢,我想一提到配置。大家都知道要么是通过XML文件来实现或者是通过泛型集合来做。我们这里可以提供的方案是这样的,通过工厂初始化时从配置文件中读取配置项,构造一个字典,然后从这个字典中查询要创建的类型是否在字典中,如果在字典中存在则创建这个类型的对象,否则返回NULL,我们这里通过泛型来实现。
- 我们来看看具体的代码实现吧:
///
/// 定义抽象工厂接口
///
public interface IAbstractFactory
{
///
/// 通用的泛型对象创建工厂
///
///
///
T Create();
}给出具体的实现这个接口的抽象工厂类
///
/// 具体的通用工厂实现
///
public class AbstractFactory : IAbstractFactory
{
private static readonly IDictionary<Type, Type> instances = null;public static AbstractFactory()
{
//从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。
//这里推荐的做饭是从配置文件中读取。
instances = new Dictionary<Type, Type>();
instances.Add(Type.GetType(“”), Type.GetType(“”));
instances.Add(Type.GetType(“”), Type.GetType(“”));
}
public T Create()
{
if (!instances.ContainsKey(typeof(T)))
return default(T);Type typeInstance = instances[typeof(T)];
T obj = (T)Activator.CreateInstance(typeInstance);
return obj;
}
}
- 通过上面给出的代码,基本上可以满足一般项目的需求,大家当然有好的思路和建议也可以提出,给出更好的改进方案,下面我给出大概的配置文件格式,其实就是父子级节点,父级节点是负责创建的工厂
- 类,那么这个父节点下的子节点就是工厂要创建的具体的对象类型。
上图中描述的思路,我们大概知道了,对应这样的一个支持多个具有依赖关系或者组合关系的对象的动态抽象工厂的实现,那么如果我们想实现支持多个具有依赖关系或者组合
关系的不同的创建形式的通用创建工厂时,我们如何来做呢?同上面的思路,只不过我们外部需要再添加一个字典,负责类型和抽象工厂的映射,即抽象工厂可以创建的字典列
表及抽象工厂具体实例类型之间的键值对关系,或者通过配置文件来组织父子级的关系。我们大概的看下配置文件的组织吧:
<?xml version="1.0" encoding="utf-8" ?>
那么具体的抽象工厂的代码又如何组织呢?如下形式:
///
/// 具体的通用工厂实现
///
public class AbstractFactory : IAbstractFactory
{
///
/// 工厂与工厂能够创建的对象类型字典之间的映射字典
///
private static readonly IDictionary<Type, Dictionary<Type, Type>> typeMapper = null;
private Type factoryType = null;
public static AbstractFactory()
{
//从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。
//这里推荐的做饭是从配置文件中读取。
//根据配置文件中的ObjectInstance 节点放在对应的工厂下的字典中
//每个工厂节点FactorySection 就会创建一个字典,并且将这个工厂能够创建的类型放在这个字典中
typeMapper = new Dictionary<Type, Dictionary<Type, Type>>();
}public AbstractFactory(string typeName)
{
this.factoryType = Type.GetType(typeName);
}
public T Create()
{
if(typeMapper.ContainsKey(this.factoryType))
return default(T);Dictionary<Type, Type> instances = typeMapper[this.factoryType];
if (!instances.ContainsKey(typeof(T)))
return default(T);Type typeInstance = instances[typeof(T)];
T obj = (T)Activator.CreateInstance(typeInstance);
return obj;
}
}通过上面的代码我们就给出了一个通用的抽象工厂的可行的解决方案。
5.2、通过委托来实现工厂模式
我们先要定义一个委托:
public delegate string DelegateFunctionHandler(string userName);
基于这个委托的工厂实现方案
///
/// 具体的通用工厂实现
///
public class DegelateFactory
{
private DelegateFunctionHandler handler = null;public static DelegateFunctionHandler Create()
{
if (handler == null)
handler = new DelegateFunctionHandler(this.Test);return handler;
}public string Test(string name)
{
return “Test!”;
}}
工厂返回一个委托类型的对象,当然我上面为了简单给出的test方法其实就是工厂内部的方法,当然这里还可以进行相应的改进,也可以通过配置文件来完成,通过配置文件把相应相
应的委托事件方法,通过配置来通过工厂动态的创建。下面给出个思路吧,具体的实现我就不贴出来了:
也希望大家给出更好的实现思路和方案。希望能多多的交流。
六、抽象工厂模式使用总结
通过上面的实现方式和思路,我们来对比一下抽象工厂、工厂模式、简单工厂模式之间的差异和相同点。
相同点:
1、都是为客户调用程序与具体的对象类型之间提供了一个解耦作用,这里怎么说呢?其实就是应用程序不关心这个对象是怎么出来的,只关系如何使用这个对象,而且以后就算对象发生变化,那么也不需
要修改用户应用程序的代码。
2、提高了程序的可维护性和低耦合性。
异同点:
1、简单工厂模式:是简单的一些列没有任何依赖关系的对象的创建,内部包含复杂的逻辑关系,一半是通过配置或者参数来进行创建对象,适合对象类型不多,并且不会经常新增的情况下。
工厂模式:每个工厂负责具体类型对象的创建,提供了可以动态新增产品类型的创建,并不需要修改现有的程序就可以无缝的新增产品类型。
抽象工厂模式:支持动态的新增对象类型和新增工厂类型,实现多种依赖关系的对象或者组合关系的创建,适合现有项目中的对象创建过程。
2、简单工厂模式:内部逻辑复杂,不符合高内聚的原则。
工厂模式:每次新增一个对象类型,就必须新增一个对应的创建工厂,无疑这是一个非常大的工作量。
抽象工厂模式:是在简单工厂模式的基础上经过改进具有前2个模式的优点,又屏蔽了他们的一些缺点。
当然我们在具体的项目中,还是需要具体的情况具体分析,一般情况下,我们对于这种数据库平滑迁移时,简单工厂可能比其他2类工厂更容易做,也很灵活。
七、系列进度。
创建型
1、系统架构技能之设计模式-单件模式
2、系统架构技能之设计模式-工厂模式
3、系统架构技能之设计模式-抽象工厂模式
4、系统架构技能之设计模式-创建者模式
5、系统架构技能之设计模式-原型模式
结构型
1、系统架构技能之设计模式-组合模式
2、系统架构技能之设计模式-外观模式
3、系统架构技能之设计模式-适配器模式
4、系统架构技能之设计模式-桥模式
5、系统架构技能之设计模式-装饰模式
6、系统架构技能之设计模式-享元模式
7、系统架构技能之设计模式-代理模式
行为型
1、系统架构技能之设计模式-命令模式
2、系统架构技能之设计模式-观察者模式
3、系统架构技能之设计模式-策略模式
4、系统架构技能之设计模式-职责模式
5、系统架构技能之设计模式-模板模式
6、系统架构技能之设计模式-中介者模式
7、系统架构技能之设计模式-解释器模式
八、下篇预告。
下篇将会针对创建者模式进行讲述,该模式也是创建型模式中最复杂的设计模式之一,该 模式是对一个对象的各个创建部分进行划分,最后创建出完整的对象,当然这里面的实现方式可以说还是
那几类思路,我将会给出几个方案的关键代码,希望大家多提宝贵意见,错误之处还请指出,请大家继续支持。
转自:https://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html
相关文章:
系统架构技能之设计模式-抽象工厂模式
一、上篇回顾 上篇我们主要讲述了简单工厂模式和工厂模式。并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下: 简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建。 工厂模式&…...
clangd的使用,实现跳转提示
一、插件卸载c插件下载clangd 二、设置搜索clangd --compile-commands-dirbuild文件中compile_commands的绝对路径若没有找到compile_commands.json文件可以通过如下方式之后再便于即可生成 cmake项目: 在项目最顶层的.cmake文件中或者CMakeList文件中加入如下命令…...
2023应届生java面试搞笑之一:CAS口误说成开心锁-笑坏面试官
源于:XX网,如果冒犯,表示歉意 面试官:什么是CAS 我:这个简单,开心锁 面试官:WTF? 我:一脸自信,对,就是这个 面试官:哈哈大笑ÿ…...
nginx-concat
为了减少tcp请求数量,nginx从上有服务器获取多个静态资源(css,js)的时候,将多个静态资源合并成一个返回给客户端。 这种前面有两个问号的请求都是用了cancat合并功能。 先到官网下载安装包,拷贝到服务器编译…...
Java 大厂面试 —— 常见集合篇 List HashMap 红黑树
23Java面试专题 八股文面试全套真题(含大厂高频面试真题)多线程_软工菜鸡的博客-CSDN博客 常见集合篇-01-集合面试题-课程介绍 02-算法复杂度分析 2 List相关面试题 2.1 数组 2.1.1 数组概述 数组(Array)是一种用连续的内存空…...
剪枝基础与实战(5): 剪枝代码详解
对模型进行剪枝,我们只对有参数的层进行剪枝,我们基于BatchNorm2d对通道重要度 γ \gamma γ参数进行稀释训练。对BatchNorm2d及它的前后层也需要进行剪枝。主要针对有参数的层:Conv2d、BatchNorm2d、Linear。但是我们不会对Pool2d 层进行剪枝,因为Pool2d只用来做下采样,没…...
Acwing 897. 最长公共子序列 (每日一题)
最长公共子序列 题目描述 给定两个长度分别为 N 和 M 的字符串 A 和 B,求既是 A 的子序列又是 B 的子序列的字符串长度最长是多少。 输入格式 第一行包含两个整数 N和 M。 第二行包含一个长度为 N 的字符串,表示字符串 A。 第三行包含一个长度为 M …...
CSS中border-radius的来美化table的实战方案
border-radius是一种CSS属性,用于设置元素的边框的圆角程度。其具体的用法如下: 设置一个值:可以为元素设置一个单一的圆角半径,这个半径将应用于元素的四个角。例如: div {border-radius: 10px; }设置四个值&#x…...
移除链表元素_每日一题
“路虽远,行则将至” ❤️主页:小赛毛 ☕今日份刷题:移除链表元素 题目描述: 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 示例1&…...
spring boot + Consul 示例 (Kotlin版)
文章目录 1.docker 安装consul2.创建基于springboot的client2.1 依赖版本2.2 pom.xml2.3 启动类2.4 application.properties 3 搭建完成4. 总结 1.docker 安装consul docker-compose.yaml version: "3"services:consul:image: consul:1.4.4container_name: consule…...
Git企业开发控制理论和实操-从入门到深入(四)|Git的远程操作|Gitee
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…...
SpringCloudAlibaba Gateway(二)详解-内置Predicate、Filter及自定义Predicate、Filter
Predicate(断言) Predicate(断言),用于进行判断,如果返回为真,才会路由到具体服务。SpirnngCloudGateway由路由断言工厂实现,直接配置即生效,当然也支持自定义路由断言工厂。 内置路由断言工厂实现 SpringClo…...
调用chat-gpt
调用chat-gpt 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifact…...
Element组件浅尝辄止6:Dialog 对话框组件
Dialog 对话框组件:在保留当前页面状态的情况下,告知用户并承载相关操作。 大白话就是弹窗组件,日常开发中比较常见 1.怎样使用? //触发方式 <el-button type"text" click"dialogVisible true">打开&…...
Bert和LSTM:情绪分类中的表现
一、说明 这篇文章的目的是评估和比较 2 种深度学习算法(BERT 和 LSTM)在情感分析中进行二元分类的性能。评估将侧重于两个关键指标:准确性(衡量整体分类性能)和训练时间(评估每种算法的效率)。…...
【面试经典150题】跳跃游戏
题目链接 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 1 < nums…...
【Rust】003-基础语法:流程控制
【Rust】003-基础语法:流程控制 文章目录 【Rust】003-基础语法:流程控制一、概述二、if 表达式1、语法格式2、多个3、获取表达式的值 三、循环1、loop:无限循环,可跳出无限循环跳出循环返回值 2、while:条件循环&…...
0829【综述】面向时空数据的区块链研究综述
摘要:时空数据包括时间和空间2个维度,常被应用于物流、供应链等领域。传统的集中式存储方式虽然具有一定的便捷性,但不能充分满足时空数据存储及查询等要求,而区块链技术采用去中心化的分布式存储机制,并通过共识协议来保证数据的安全性。研究现有区块链1.0、2.0和以Block-DAG为…...
MySQL高级篇(SQL优化、索引优化、锁机制、主从复制)
目录 0 存储引擎介绍1 SQL性能分析2 常见通用的JOIN查询 SQL执行加载顺序七种JOIN写法3 索引介绍 3.1 索引是什么3.2 索引优劣势3.3 索引分类和建索引命令语句3.4 索引结构与检索原理3.5 哪些情况适合建索引3.6 哪些情况不适合建索引4 性能分析 4.1 性能分析前提知识4.2 Expla…...
YOLOV8模型使用-检测-物体追踪
这个最新的物体检测模型,很厉害的样子,还有物体追踪的功能。 有官方的Python代码,直接上手试试就好,至于理论,有想研究在看论文了╮(╯_╰)╭ 简单介绍 YOLOv8 中可用的模型 YOLOv8 模型的每个类别中有五个模型用于检…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...


