上篇文章,我们说到了简单工厂和工厂方法,如果没看过的,请先看上篇,不然的话,可能有些吃力,或者直接点击阅读原文,查看我博客园的对应详细版的文章。

大家学到了这里,我建议自己可以练习练习,可以写一下部分代码,很好的区分下【简单工厂】和【工厂方法】之间的区别和练习,如果说你已经看懂了,或者说自己已经练习好了,那咱们就继续往下说今天的重要内容 —— 抽象工厂。

再说抽象工厂之前呢,咱们先简单总结一下:

1、我们知道,工厂模式属于创建型开发模式的一元,他的作用就是创建我们需要的对象,如果一个一个创建的话,会很麻烦,所以我们诞生出来了一个【简单工厂】,这个简单工厂只是简单的人为的把几个对象的实例给堆起来,通过type 来区分,然后分别 new 实例化,有时候也是一个很好的方案,但是这样有一个弊端,违背了我们开发六大原则中的——OCP开放关闭原则,所以这个时候,我们就又多出来一个新的概念【工厂方法】。

2、【工厂方法】是在【简单工厂】的基础上,做了相应的改良——通过多个子类的形式,来替换之前的 type 分类法,对内修改关闭,对外新增打开,这样无论是代码整洁上,还是扩展封装上,都有了很好的体验,同时也满足了我们的OCP开发原则。

3、但是!这种方案真的就很好了么,我们再来回忆一下,我们无论是简单工厂,还是工厂方法,都是生成的单独的一个类,好处是可以一一的慢慢扩展,但归根结底还是在处理一个类,我们平时开发的时候,处理一个类是很多,比如常见的helper,Log 之类的。但是这不是我们开发的重点,我们平时使用最多的还是 Service 类,或者 Repository 类,里边有很多,各种各样的的类,比如 User 表,Role 表,Permission 表等等,每一个实体又都对应各自的一个服务类或者仓储类。

4、那这个时候,我们使用上边的【工厂方法】还行么?肯定是不行的!因为我们上边是一个二维体系,EFCoreRepository 、SugarRepository、DapperRepository等等,是这样的二维,我们现在要做的就是在这个二维的基础上,再加上一个维度,就是要解决 User 、Role、Permission 实体等等这种一组或者一系列的类创建的问题。

5、那就是今天下边要说到的【抽象工厂】模式。

注意,下边的例子可能不太恰当,只是作为理解抽象工厂模式来使用,具体开发中,可能有出入。

这篇文章内容不是很全,我在博客园重新编排了一下,然后也同时加上了一个小故事,更方便理解,大家可以点击【阅读原文】来查看。

一、抽象工厂模式

上边的问题我们都看到了,我们要解决一系列一组类创建的问题,引申出来了抽象工厂模式,那下边我们就简单写一些代码,看看是否跑的通。

1、创建一个核心层,添加多个仓储操作

我们毕竟要操作数据库嘛,所以肯定需要仓储来持久化,那我们就创建一个 FactoryPattern.Core 层,用来存放我们整个项目核心的底层。首先要创建的就是几个仓储:

/// <summary>/// 定义抽象的基类仓储/// </summary>public abstract class BaseRepository{    /// <summary>    /// 创建    /// </summary>    public abstract void Add();    /// <summary>    /// 删除    /// </summary>    public abstract void Delete();    /// <summary>    /// 修改    /// </summary>    public abstract void Update();    /// <summary>    /// 查询    /// </summary>/    public abstract void Query();}  /// <summary>  /// 定义抽象用户仓储,继承抽象基类仓储  /// 抽象的目的,是为了给UserRepositoryEFCore、UserRepositorySugar、  /// 做父类  /// </summary>  public abstract class UserRepository: BaseRepository  {  } /// <summary> /// 同 UserRepository /// </summary> public abstract class RoleRepository: BaseRepository { } /// <summary> /// 同 UserRepository /// </summary> public abstract class PermissionRepository: BaseRepository { }
 

那基本的仓储都已经定义好了,现在就需要一个工厂来生产这一系列产品了,所以我们定义一个抽象工厂类:

 /// <summary> /// 抽象工厂类,提供创建不同仓储接口 /// </summary> public abstract class AbstractFactory {     // 抽象工厂提供创建一系列产品的接口     public abstract UserRepository UserRepository();     public abstract RoleRepository RoleRepository();     public abstract PermissionRepository PermissionRepository(); }

结构如下:

2、创建EFCore仓储工厂层

说人话就是,刚刚我们不是定义了一个抽象的工厂么,用来生产我们数据库中一系列一组的产品,也就是数据库表,那现在我们就需要指定具体的工厂来生产他们了,首先第一个我们就用EFCore这个工厂来生产,创建一个 FactoryPattern.Repository.EFCore 类库,并引用 Core 核心层

首先呢,我们就要在这一层中,对那几个抽象的仓储类做重写,对应每一个EFCore 版本的仓储类,可能你会问为什么,要每一个重写下,还是OCP原则,而且还有一个愿意,Sqlsugar 可能某些表达式查询,在EFCore里不能用,所以必须每一个重写出来。

这里有一个地方就是,可以在EFCore也针对基类仓储做一个基类的,但是后来有类型不一致问题,大家可以自己看看.

 /// <summary> /// EFCore User 仓储,继承User仓储 /// </summary> public class UserRepositoryEFCore : UserRepository {     public override void Add()     {         throw new NotImplementedException();     }     public override void Delete()     {         throw new NotImplementedException();     }     public override void Query()     {         throw new NotImplementedException();     }     public override void Update()     {         throw new NotImplementedException();     } }// 其他两个表也是这个情况,不粘贴代码了。

那现在有了子仓储产品了,我们就开始加工生产了,创建 EFCoreRepositoryFactory.cs ,并继承抽象工厂,同时实现抽象方法:

 /// <summary> /// EFCore 仓储子工厂 /// 用来生产各个实体仓储 /// </summary> public class EFCoreRepositoryFactory : AbstractFactory {     public override PermissionRepository PermissionRepository()     {         return new PermissionRepositoryEFCore();     }     public override RoleRepository RoleRepository()     {         return new RoleRepositoryEFCore();     }     public override UserRepository UserRepository()     {         return new UserRepositoryEFCore();     } }

结构如下:

3、同理,创建Sugar仓储工厂层

过程和上边的一模一样,我就不多说了,整体结构还是这样的:

4、控制器调用实例

我们在 api 层,引用刚刚创建的两个仓储层项目:

然后开始调用:

[HttpGet]public void Get(){    // 实例化工厂,这里用来生产 efcore 这一系列的 产品    AbstractFactory efcoreFactory = new EFCoreRepositoryFactory();    efcoreFactory.UserRepository().Add();    efcoreFactory.RoleRepository().Delete();    efcoreFactory.PermissionRepository().Query();    // 实例化工厂,这里用来生产 sugar 这一系列的 产品    AbstractFactory sugarFactory = new SugarRepositoryFactory();    sugarFactory.UserRepository().Add();    sugarFactory.RoleRepository().Delete();    sugarFactory.PermissionRepository().Query();}

结果我就不调试,肯定是没有问题的,毕竟仅仅是类的调用嘛,如果说你从上边往下看,看到了这里,还没有问题,并且能大概明白其中的意义,那你的工厂模式已经完全学会了,特别是这个抽象工厂,一直很绕,而且也使用的不是很直观,用途不是很多。

现在我们再简单的说明一下,我们通过【抽象工厂】模式,慢慢的明白了,其实抽象工厂是在【工厂方法】模式的基础上,往外又多做了一套封装,目的就是解决生产一系列产品的时候,工厂方法无法满足的问题。

所以这个时候,如果有人问你二者的区别,核心的区别就是:如果是一个产品用工厂方法,一系列产品,用抽象工厂

但是虽然解决了问题,还是有很多的问题的,单单从上边我们创建了那么多的子类,以及子类必须重写这一点来看,这么设计肯定有弊端,那有什么改进的呢?咱们继续往下看

二、抽象工厂与依赖注入

这里我就不详细说了,其实就是一个思路的用法,这里举个例子就行了,大家肯定都用过三层架构,其中有一个数据访问层 DALFactory ,我们平时使用的时候,就是直接把类的实例给 return 出来,如果我们同时连接多个数据库呢?那这样的话,我们就像上边说到的,建立多个 DAL 层,比如 DALSqlServer、DALMysql 等等,那我们如何通过接口来获取服务呢,就是通过反射指定的程序集来实现,这个就是简单的使用了抽象工厂。

比如这个网上的图片,就是这个意思,大家看个意思就行:

说到这里大家有没有了解到一些小小的心得,似乎这个和有一个东西很像!对!就是我们平时使用的依赖注入。其实我们可以想一想,我们在服务注册的时候,通过反射将多个服务注册到容器里,然后我们再使用的时候,是容器通过接口别名,给我们找到指定的具体服务,甚至也实现了一个接口,多个服务的操作,这个就是工厂模式和依赖注入的小小的关系。

总结一下:

今天我们通过简单的代码,一步一步,从【简单工厂】开始,了解到了多个类是如何创建的,然后明白了【工厂方法】模式,更好的实现了OCP原则,也实现了封装多态的原理,接下来咱们通过【抽象工厂】的举例,进一步对一系列一组产品生产的时候,所采用的方案,到最后,我们简单的说明了一下反射以及依赖注入和工厂模式的关系,可能读起来还是有点儿凌乱,不过我还是简单大家多多的学学,查查资料,因为我认为,设计模式是结构的基础,而工厂模式又是设计模式的基础,可见其重要性,如果看不懂没关系,等我直播讲课吧。

当然抽象工厂也是有一些弊端的,比如:

 3.1】、抽象工厂模式的优点:【抽象工厂】模式将系列产品的创建工作延迟到具体工厂的子类中,我们声明工厂类变量的时候是使用的抽象类型,同理,我们使用产品类型也是抽象类型,这样做就尽可能的可以减少客户端代码与具体产品类之间的依赖,从而降低了系统的耦合度。耦合度降低了,对于后期的维护和扩展就更有利,这也就是【抽象工厂】模式的优点所在。可能有人会说在Main方法里面(这里的代码就是客户端的使用方)还是会使用具体的工厂类,对的。这个其实我们通过Net的配置,把这部分移出去,最后把依赖关系放到配置文件中。如果有新的需求我们只需要修改配置文件,根本就不需要修改代码了,让客户代码更稳定。依赖关系肯定会存在,我们要做的就是降低依赖,想完全去除很难,也不现实。

 3.2】、抽象工厂模式的缺点:有优点肯定就有缺点,因为每种模式都有他的使用范围,或者说要解决的问题,不能解决的问题就是缺点了,其实也不能叫缺点了。【抽象工厂】模式很难支持增加新产品的变化,这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了“开发——封闭”原则。

3.3】、抽象工厂模式的使用场景:   如果系统需要多套的代码解决方案,并且每套的代码方案中又有很多相互关联的产品类型,并且在系统中我们可以相互替换的使用一套产品的时候可以使用该模式,客户端不需要依赖具体实现。

三、示例代码

https://github.com/anjoy8/DesignPattern/tree/master/FactoryPattern

【参考文献:】

1、Dependency Injection vs Factory Pattern

身边的设计模式(三):抽象工厂 与 依赖注入相关推荐

  1. 设计模式三—抽象工厂模式

    设计模式三-抽象工厂模式 一.定义 抽象工厂模式是工厂方法模式的进一步抽象.如果产品簇中只有一种产品,则退化为工厂方法模式. 二.原理图 三.代码实例 * 苹果和土豆是园丁1的杰作 * 葡萄和西红柿是 ...

  2. 浅析设计模式(三)——抽象工厂模式

    抽象工厂模式(Abstract-Factory,创建型模式) 本文的结构: 一.抽象工厂模式的定义 二.抽象工厂模式的参与者及其角色 三.抽象工厂模式的类图 四.抽象工厂模式的示例 五.参考 一.抽象 ...

  3. 抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化

    分层思想的一个核心就是部件化,各个层之间是相互独立的,每一层可以随便抽取换成一个其他语言的版本,但只要与相应的接口吻合就行. 我用的三层架构大致是这样的,基本的三层就不说了,然后分别为业务逻辑层和数据 ...

  4. 设计模式之四(抽象工厂模式第三回合)

    原文:设计模式之四(抽象工厂模式第三回合) 前言 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂模式最大的好处便是易于交换产品系列,由于具体工厂类,例如I ...

  5. C#设计模式(4)——抽象工厂模式

    C#设计模式(4)--抽象工厂模式 一.引言 在上一专题中介绍了工厂方法模式,工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增加需要增加额外的代码),而工厂方法 ...

  6. 工厂设计模式、简单工厂设计模式、抽象工厂设计模式

    一.简单工厂设计模式.工厂设计模式,抽象工厂设计模式总体分析 简单工厂模式 简单工厂模式不是23种里的一种,简而言之,就是有一个专门生产某个产品的类. 比如下图中的鼠标工厂,专业生产鼠标,给参数0,生 ...

  7. 设计模式系列·抽象工厂模式

    前言 以小说的笔法写的设计模式系列文章,你绝对看得懂![首发于公众号:"聊聊代码"] 设计模式系列·王小二需求历险记(一) 设计模式系列·王小二需求历险记(二) 设计模式系列·封装 ...

  8. 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)

    原文:乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern) [索引页] [源码下载] 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Facto ...

  9. 设计模式-04抽象工厂模式

    设计模式-04抽象工厂模式 文章中涉及到的代码,请自行下载 https://gitee.com/pan_xiao_lei123/designmode.git 前面介绍的工厂方法模式中考虑的是一类产品的 ...

最新文章

  1. 美团智能问答技术探索与实践
  2. C#中把货币、日期转换成中文大写
  3. CentOS7修改默认运行级别
  4. Leetcode--494. 目标和
  5. 【jQuery笔记Part1】09-jQuery操作css-尺寸
  6. python thread start_Python中Thread类的start和run方法的区别
  7. 推荐两个适合代码的字体
  8. 最新C语言编程软件推荐(2021整理)
  9. 使用filezilla server搭建ftp服务器
  10. 逻辑表达式在c语言中作用,C语言中逻辑表达式与关系表达式的值
  11. ocx注册以及检测(转)
  12. 工控蜜罐 Conpot 的进阶玩法
  13. 把手机作为网站服务器,如何利用废旧手机打造网站服务器
  14. 36周岁这年,我终于知道该怎么活了!
  15. .net framework 4.0 在 VS2010 安装目录下位置 dotNetFx40_Full_x86_x64.exe在磁盘哪个目录?...
  16. 服务器响应404,无法加载资源错误:服务器响应状态为404(未找到)
  17. 传输层的主要功能和协议
  18. vue中使用woo.js + animate.css
  19. 普乐蛙5d车载影院5d飞行影院5d轨道影院体验馆
  20. maven依赖中部分依赖出现深灰色可能的解决方案

热门文章

  1. Gruntjs: grunt-contrib-jst
  2. Java原来如此-随机数
  3. Execute .NET Code under SQL Server 2005
  4. js javaScript array 取指定元素索引、判断是否相同、重复、过滤数据
  5. c# 类的基本知识,未完,待续
  6. MATLAB编程与应用系列-关于MATLAB编程入门教程的总体编写安排
  7. 前端几个笔试题及答案(bd)
  8. Dapr + .NET 实战(五)Actor
  9. .NET Core etcd 配置源
  10. 基于ABP落地领域驱动设计-05.实体创建和更新最佳实践