系统架构技能之设计模式-抽象工厂模式

一、上篇回顾

上篇我们主要讲述了简单工厂模式和工厂模式。并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下:

简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建。

工厂模式:多个工厂负责多个类型对象的创建,每个工厂只负责具体类型对象的创建,支持无缝的新增类型对象的创建,需要实现工厂接口类和具体的类型对象类。

我们来简单的对比下这2个模式的优缺点:

模式名称优点缺点
简单工厂模式一个工厂负责所有对象的创建,简单灵活不符合高内聚的原则,不支持无缝的扩展
工厂模式可以无缝的新增类型,每个工厂职责单一,符合高内聚的原则工厂类太多,难以维护。

工厂模式,很优雅的解决了应用程序使用对象时的无限new()的操作,同时降低了系统应用之间的耦合性,提高了系统的可维护性和适应性。

二、摘要

本文主要是针对创建型模式中的抽象工厂模式进行讲述,抽象工厂模式是在简单工厂模式的基础上扩展而成的新模式,将简单工厂中的对象的创建过程进行了很优雅的动态配置来完成无

缝的扩展,当然通过一些扩展,可以构建出可支持动态新增或者删除对象的抽象工厂模式。本文将会给出具体的实现方案,相比工厂模式,抽象工厂模式是一个工厂负责多个对象的创建,返回

的具体的类型是这个对象的抽象类型。这样,在客户端引用的时候只需要使用这个工厂返回的对象类型,抽象工厂会自动根据对象的类型动态的创建这个类型对象的实例。大体的过程如下:

image

上面的图片呢,主要是针对经典的抽象工厂模式给出了一个实现草图的模拟,而我们在实际的项目中可能并不希望给出这么多的抽象工厂工厂实现,我只想给出一个通用的抽象

工厂实现,通过静态方法直接调用,返回我想要的对象类型的实例,而且这个对象类型是可以动态配置的,那么我们如何做到呢?这就是本篇需要讨论的实现方案。本篇将会从

以下几点进行讲述抽象工厂模式:

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;
}
}

  • 通过上面给出的代码,基本上可以满足一般项目的需求,大家当然有好的思路和建议也可以提出,给出更好的改进方案,下面我给出大概的配置文件格式,其实就是父子级节点,父级节点是负责创建的工厂
  • 类,那么这个父节点下的子节点就是工厂要创建的具体的对象类型。

image

上图中描述的思路,我们大概知道了,对应这样的一个支持多个具有依赖关系或者组合关系的对象的动态抽象工厂的实现,那么如果我们想实现支持多个具有依赖关系或者组合

关系的不同的创建形式的通用创建工厂时,我们如何来做呢?同上面的思路,只不过我们外部需要再添加一个字典,负责类型和抽象工厂的映射,即抽象工厂可以创建的字典列

表及抽象工厂具体实例类型之间的键值对关系,或者通过配置文件来组织父子级的关系。我们大概的看下配置文件的组织吧:

<?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方法其实就是工厂内部的方法,当然这里还可以进行相应的改进,也可以通过配置文件来完成,通过配置文件把相应相

应的委托事件方法,通过配置来通过工厂动态的创建。下面给出个思路吧,具体的实现我就不贴出来了:

image也希望大家给出更好的实现思路和方案。希望能多多的交流。

六、抽象工厂模式使用总结

通过上面的实现方式和思路,我们来对比一下抽象工厂、工厂模式、简单工厂模式之间的差异和相同点。

相同点:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/118487.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

githubPage部署Vue项目

github中新建项目 my-web &#xff08;编写vue项目代码&#xff09; myWebOnline(存放Vue打包后的dist包里面的文件) 发布流程 &#xff08;假设my-web项目已经编写完成&#xff09;Vue-cli my-web vue.config.js文件中 const { defineConfig } require(vue/cli-service)…

求解整数规划问题的割平面法和分支定界法

文章目录 整数规划割平面法分支定界法代码实现 整数规划 整数规划问题是优化变量必须取整数值的线性或非线性规划问题&#xff0c;不过&#xff0c;在大多数情况下&#xff0c;整数规划问题指的是整数线性规划问题。 其数学模型为 m i n f ( x ) c T x s.t A x b x ≥ 0 x…

JVM类的加载过程

加载过程 JVM的类的加载过程分为五个阶段&#xff1a;加载、验证、准备、解析、初始化。 加载   加载阶段就是将编译好的的class文件通过字节流的方式从硬盘或者通过网络加载到JVM虚拟机当中来。&#xff08;我们平时在Idea中书写的代码就是放在磁盘中的&#xff0c;也可以通…

Mysql主从服务安装配置

1.下载地址 MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/ 2.安装配置 1.下载解压后&#xff0c;拷贝一份作为slave的安装目录 3.配置my.ini 由于下载mysql8版本&#xff0c;解压后&#xff0c;没有相关的my…

Spark有两种常见的提交方式:client 模式和 cluster 模式对机器 CPU 的影响

Spark有两种常见的提交方式&#xff1a;client 模式和 cluster 模式。这两种方式对机器 CPU 的影响略有不同 &#xff0c;请参考以下说明 Client 模式&#xff1a; 在 Client 模式下&#xff0c;Spark Driver 运行在提交任务的客户端节点上&#xff08;即运行 spark-submit 命…

企业数据加密软件——「天锐绿盾」

「天锐绿盾」是一款企业数据加密软件&#xff0c;主要用于防止企业计算机信息被破坏、丢失和泄密。该软件采用文件过滤驱动实现透明加解密&#xff0c;对用户完全透明&#xff0c;不影响用户操作习惯。 PC访问地址&#xff1a; isite.baidu.com/site/wjz012xr/2eae091d-1b97-4…

Laravel 模型1对1关联 1对多关联 多对多关联 ⑩①

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; THINK PHP &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

DNS原理

文章目录 一、域名产生背景域名的树形层次化结构 二、定义三、DNS查询模式递归查询迭代查询 四、主机域名解析工作流程五、H3C配置DNS代理 首先可以看下思维导图&#xff0c;以便更好的理解接下来的内容。 一、域名 产生背景 在互联网中&#xff0c;通过IP地址访问目标主机…

Python:多变量赋值

相关文章 Python专栏https://blog.csdn.net/weixin_45791458/category_12403403.html?spm1001.2014.3001.5482 Python中的赋值语句可以同时对多个变量进行对象绑定&#xff08;赋值&#xff09;&#xff0c;既可以是多变量链式赋值&#xff0c;也可以是多变量平行赋值&#x…

【LeetCode75】第四十二题 删除二叉搜索数中的节点

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一棵二叉搜索树&#xff0c;给我们一个目标值&#xff0c;让我们删除节点值等于目标值的节点&#xff0c;并且删除之后需要保持…

React 18 在组件间共享状态

参考文章 在组件间共享状态 有时候&#xff0c;希望两个组件的状态始终同步更改。要实现这一点&#xff0c;可以将相关 state 从这两个组件上移除&#xff0c;并把 state 放到它们的公共父级&#xff0c;再通过 props 将 state 传递给这两个组件。这被称为“状态提升”&#…

ELK安装、部署、调试(一)设计规划及准备

一、整体规划如图&#xff1a; 【filebeat】 需要收集日志的服务器&#xff0c;安装filebeat软件&#xff0c;用于收集日志。logstash也可以收集日志&#xff0c;但是占用的系统资源过大&#xff0c;所以使用了filebeat来收集日志。 【kafka】 接收filebeat的日志&#xff…

Docker从认识到实践再到底层原理(二-1)|容器技术发展史+虚拟化容器概念和简介

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

数据结构(Java实现)-Map和Set

搜索树 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的左右子树也…

Python爬虫-某网酒店数据

前言 本文是该专栏的第5篇,后面会持续分享python爬虫案例干货,记得关注。 本文以某网的酒店数据为例,实现根据目标城市获取酒店数据。具体思路和方法跟着笔者直接往下看正文详细内容。(附带完整代码) 正文 地址:aHR0cHM6Ly93d3cuYnRoaG90ZWxzLmNvbS9saXN0L3NoYW5naGFp …

105. 从前序与中序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 思路&#xff1a;题目给出了先序遍历和中序遍历的结果&#xff0c;因为先序遍历遵循根–>左–>…

继承【C++】

文章目录 继承的概念继承的定义继承方式和访问限定符继承基类成员访问方式的变化 默认继承方式 基类和派生类对象赋值转换继承中的作用域派生类的默认成员函数继承与友元静态成员菱形继承及菱形虚拟继承继承的方式 菱形虚拟继承菱形虚拟继承原理 继承的概念 继承(inheritance)…

自建音乐服务器Navidrome之二

6 准备音乐资源 可选 Last.fm Lastfm是 Audioscrobbler 音乐引擎设计团队的旗舰产品&#xff0c;以英国为总部的网络电台和音乐社区。有遍布232个国家超过1500万的活跃听众。据说有6亿音乐资源。 docker-compose.yml 配置 Navidrome 可以从 Last.fm 和 Spotify 获取专辑信息和…

用 ChatGPT 写代码太省时间了

几个月前&#xff0c;我们聊过陶哲轩使用 ChatGPT 辅助解决数学问题。当时&#xff0c;他觉得虽然测试结果不太令人满意&#xff0c;但也并没有对 ChatGPT 持完全否定的态度。他觉得&#xff0c;像 ChatGPT 这类大型语言模型在数学中可以用来做一些半成品的语义搜索工作&#x…

iOS开发Swift-4-IBAction,group,音乐播放器-木琴App

1.使用素材创建木琴App的UI。 2.连接IBAction。 其余按钮直接拖拽到play里边。 当鼠标置于1处时2处显示如图&#xff0c;表示成功。当用户按下任一按钮都会触发play中的内容。 3.将7个按钮的View中的Tag值分别调为1、2、3、4、5、6、7. 4.将音频文件拖入项目文件中。 Create gr…