C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】

C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】,第1张

概述一、引言 写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力。今天我要写第四个模式了,该模式叫抽象工厂。上一篇文章我们讲了【工厂方法】模式,它是为了解决【简

一、引言

     写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力。今天我要写第四个模式了,该模式叫抽象工厂。上一篇文章我们讲了【工厂方法】模式,它是为了解决【简单工厂】模式所面对的问题,它的问题就是:如果我们增加新的产品,工厂类的方法就要修改本身的代码,增加产品越多,其逻辑越复杂,同时这样的修改也是不符合【开放关闭原则OCP】,对修改代码关闭,对增加代码开放。为了解决【简单工厂】的问题,我们引出了【工厂方法】模式,通过子类化工厂类,解决了工厂类责任的划分,产品和相应的工厂一一对应,符合了OCP。如果我们要设计一套房子,当然我们知道房子是由房顶、地板、窗户、房门组成的,别的组件暂时省略,先设计一套古典风格的房子,再创建一套现代风格的房子,再创建一套欧式风格的房子,这么多套房子,我们该怎么办呢?今天我们要讲的【抽象工厂】模式可以很好的解决多套变化的问题。

二、抽象工厂详细介绍

  2.1、动机(Motivate):

     在软件系统中,经常面临着"一系统相互依赖的对象"的创建工作:同时,由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种"封装机制"来避免客户程序和这种"多系列具体对象创建工作"的紧耦合?

  2.2、意图(Intent):

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。                            ——《设计模式》GoF

  2.3、结构图(Structure)

   


   该图是抽象工厂的UML图,结合抽象工厂的意图、动机和图示来理解该模式,今天我们就以建设房子为例来说明抽象工厂的实现机理。

2.4、模式的组成

      可以看出,在抽象工厂模式的结构图有以下角色:

      (1)、抽象产品类角色(AbstractProduct):为抽象工厂中相互依赖的每种产品定义抽象接口对象,也可以这样说,有几种产品,就要声明几个抽象角色,每一个抽象产品角色和一种具体的产品相匹配。

      (2)、具体产品类(ConcreteProduct):具体产品类实现了抽象产品类,是针对某个具体产品的实现的类型。

      (3)、抽象工厂类角色(Abstract Factory):定义了创建一组相互依赖的产品对象的接口 *** 作,每种 *** 作和每种产品一一对应。

      (4)、具体工厂类角色(ConcreteFactory):实现抽象类里面的所有抽象接口 *** 作,可以创建某系列具体的产品,这些具体的产品是“抽象产品类角色”的子类。


2.5、抽象工厂的具体代码实现

       随着我们年龄的增大,我们也到了结婚的年龄。结婚首要的问题就是房子的问题,假设我有一个很有钱的爸爸,哈哈,有钱可以解决很多问题。作为长子的我,希望能有一套欧式风格的房子,再加上田园风光,此生足矣。我弟弟就不一样了,他想要一套现代样式的房子,如果兄弟姊妹再多年一点,那就有更多的要求了。由于房子由房顶、地板、窗户和房门组成,其他组件暂时省略,有这么多套房子要建设,每套房子的房顶、地板、窗户和房门都是一个体系的,那就让我们看看如何使用【抽象工厂】模式来实现不同房屋的建造。

  1          /// <summary>  2         /// 下面以不同系列房屋的建造为例子演示抽象工厂模式  3          因为每个人的喜好不一样,我喜欢欧式的,我弟弟就喜欢现代的  4          客户端调用  5         </summary>  6         class ClIEnt  7         {  8             static voID Main(string[] args)  9             { 10                // 哥哥的欧式风格的房子 11                AbstractFactory europeanFactory= new EuropeanFactory(); 12                europeanFactory.CreateRoof().Create(); 13                europeanFactory.CreateFloor(). 14                europeanFactory.CreateWindow(). 15                europeanFactory.CreateDoor().Create();  16  17     18                弟弟的现代风格的房子 19                AbstractFactory modernizationFactory =  ModernizationFactory(); 20                modernizationFactory.CreateRoof().Create(); 21                modernizationFactory.CreateFloor().Create(); 22                modernizationFactory.CreateWindow().Create(); 23                modernizationFactory.CreateDoor().Create(); 24                Console.Read(); 25           } 26     } 27     28        29        抽象工厂类,提供创建不同类型房子的接口 30       31       public abstract  AbstractFactory 32      { 33           抽象工厂提供创建一系列产品的接口,这里作为例子,只给出了房顶、地板、窗户和房门创建接口 34          abstract Roof CreateRoof(); 35           Floor CreateFloor(); 36           Window CreateWindow(); 37           Door CreateDoor(); 38      } 39    40       41      欧式风格房子的工厂,负责创建欧式风格的房子 42      43      EuropeanFactory : AbstractFactory 44     { 45           制作欧式房顶 46          overrIDe Roof CreateRoof() 47          { 48               return  EuropeanRoof(); 49  50    51           制作欧式地板 52           Floor CreateFloor() 53  54               EuropeanFloor(); 55          } 56   57          制作欧式窗户 58          Window CreateWindow() 59  60               EuropeanWindow(); 61         } 62   63          制作欧式房门 64          Door CreateDoor() 65  66               EuropeanDoor(); 67  68  69    70       71      现在风格房子的工厂,负责创建现代风格的房子 72      73      ModernizationFactory : AbstractFactory 74  75           制作现代房顶 76          77  78               ModernizationRoof(); 79  80  81          制作现代地板 82         83        { 84              ModernizationFloor(); 85        } 86   87         制作现代窗户 88        89       { 90             ModernizationWindow(); 91       } 92   93        制作现代房门 94       95  96             ModernizationDoor(); 97  98   } 99    100     101      房顶抽象类,子类的房顶必须继承该类102    103     Roof104 105          106          创建房顶107        108        voID Create();109    }110   111    112    地板抽象类,子类的地板必须继承该类113   114    Floor115    {116         117         创建地板118       119      120 121   122    123    窗户抽象类,子类的窗户必须继承该类124   125     Window126 127         128         创建窗户129       130       131 132  133    134     房门抽象类,子类的房门必须继承该类135    136     Door137 138         139         创建房门140       141       142 143   144    145    欧式地板类146   147    EuropeanFloor : Floor148 149       overrIDe  Create()150 151           Console.Writeline("创建欧式的地板");152 153 154   155   156     157     欧式的房顶158    159     EuropeanRoof : Roof160 161          162 163             Console.Writeline(创建欧式的房顶164 165 166   167  168     169     欧式的窗户170     171      EuropeanWindow : Window172 173          174 175              Console.Writeline(创建欧式的窗户176 177 178   179   180      181      欧式的房门182    183      EuropeanDoor : Door184 185         186 187             Console.Writeline(创建欧式的房门188 189 190  191      192      现代的房顶193     194      ModernizationRoof : Roof195 196          197 198              Console.Writeline(创建现代的房顶199 200 201  202     203      现代的地板204    205      ModernizationFloor : Floor206 207         208 209              Console.Writeline(创建现代的地板210 211 212       213     214      现代的窗户215    216     ModernizationWindow : Window217 218           219 220               Console.Writeline(创建现代的窗户221 222 223  224     225      现代的房门226    227     ModernizationDoor : Door228 229         230 231             Console.Writeline(创建现代的房门232 233     }


2.6、 抽象工厂应对需求变更

  让我们看看该模式如何应对需求的变化,假设我的表弟一看我们的房子很好,他也想要一套古典风格的房子(哈哈,这个家伙事挺多的,有好事总是落不下他)。

 1      2     先为表弟的房子来建立一个工厂类吧 3      4      ClassicalFactory : AbstractFactory 5  6         创建房顶 7          8  9               ClassicalRoof();10 11 12          创建地板13         14 15               ClassicalFloor();16 17 18          创建窗户19         20 21               ClassicalWindow();22 23 24          创建房门25         26 27               ClassicalDoor();28 29 30 31     32     古典的房顶33     34       ClassicalRoof : Roof35 36         37 38             Console.Writeline(创建古典的房顶39 40 41 42     43      古典的地板44     45       ClassicalFloor : Floor46 47         48 49             Console.Writeline(创建古典的地板50 51 52  53     54      古典的窗户55     56       ClassicalWindow : Window57 58         59 60             Console.Writeline(创建古典的窗户61 62 63  64     65      古典的房门66     67       ClassicalDoor: Door68 69         70 71             Console.Writeline(创建古典的房门72 73     }


  此时,只需要添加五个类:一个是古典风格工厂类,负责创建古典风格的房子,另外几个类是具有古典风格的房顶、地板、窗户和房门的具体产品。从上面代码看出,抽象工厂对于系列产品的变化支持 “开放——封闭”原则(指的是要求系统对扩展开放,对修改封闭),扩展起来非常简便,但是,抽象工厂对于增加新产品这种情况就不支持”开放——封闭 “原则,因为要修改创建系列产品的抽象基类AbstractFactory,增加相应产品的创建方法,这也是抽象工厂的缺点所在。

三、抽象工厂的实现要点

     1、如果没有应对“多系列对象创建”的需求变化,则没有必要使用AbstractFactory模式,这时候使用简单的静态工厂完全可以。

      2、"系列对象"指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中“道路”与“房屋”的依赖,“道路”与“地道”的依赖。

      3、AbstractFactory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。

      4、AbstractFactory模式经常喝FactoryMethod模式共同组合来应对“对象创建”的需求变化。

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

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

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

四、.NET中抽象工厂模式实现

微软的类库发展了这么多年,设计模式在里面有大量的应用,【抽象工厂】模式在.NET类库中也存在着大量的使用,比如和 *** 作数据库有关的类型,这个类就是System.Data.Common.DbProvIDerFactory,这个类位于System.Data.dll程序集中。该类扮演抽象工厂模式中抽象工厂的角色,我们可以用ILSpy反编译工具查看该类的实现:

/// 扮演抽象工厂的角色
/// 创建连接数据库时所需要的对象集合,
/// 这个对象集合包括有 DbConnection对象(这个是抽象产品类,如绝味例子中的YaBo类)、DbCommand类、DbDataAdapter类,针对不同的具体工厂都需要实现该抽象类中方法,

 1  DbProvIDerFactory 2  3         virtual bool CanCreateDataSourceEnumerator 4  5             get 6  7                 false;            } 9 10 11         virtual DbCommand CreateCommand()12 13             null15 16          DbCommandBuilder CreateCommandBuilder()17 18             19 20 21          DbConnection CreateConnection()23             24 25 26          DbConnectionStringBuilder CreateConnectionStringBuilder()27 28             31          DbDataAdapter CreateDataAdapter()32 33             34 35  DbParameter CreateParameter()38             40 41          CodeAccesspermission CreatePermission(PermissionState state)42 43             44 45 46          DbDataSourceEnumerator CreateDataSourceEnumerator()47 48             49 51 }


DbProvIDerFactory类是一个抽象工厂类,该类提供了创建数据库连接时所需要的对象集合的接口,实际创建的工作在其子类工厂中进行,微软使用的是sql Server数据库,因此提供了连接Sql Server数据的具体工厂实现,具体代码可以用反编译工具查看,具体代码如下:

sqlClIEntFactory扮演着具体工厂的角色,用来创建连接Sql Server数据所需要的对象

sealed  sqlClIEntFactory : DbProvIDerFactory,IServiceProvIDerReadonly sqlClIEntFactory Instance =  sqlClIEntFactory(); 4  5          7              9                 true11 12 private sqlClIEntFactory()15 16 17         18 19              sqlCommand();21 22         23 24              sqlCommandBuilder();25 26 27         29              sqlConnection();30 31 32         33 34              sqlConnectionStringBuilder();36 37         38 39              sqlDataAdapter();42         43 44              sqlParameter();45 46 49              sqlClIEntPermission(state);51 52         53 54             return sqlDataSourceEnumerator.Instance;55 56 57         object IServiceProvIDer.GetService(Type serviceType)58 59             object result = 60             if (serviceType == GreenMethods.SystemDataCommonDbProvIDerServices_Type)62                 result = GreenMethods.SystemDatasqlClIEntsqlProvIDerServices_Instance();63 64              result;65 66     }

OdbcFactory也是具体工厂类

 OdbcFactory : DbProvIDerFactoryReadonly OdbcFactory Instance =  OdbcFactory(); OdbcFactory() 7  8  9         11              OdbcCommand();13 14         16              OdbcCommandBuilder();18  OdbcConnection();26              OdbcConnectionStringBuilder();28 29         31              OdbcdataAdapter();33 34         36              OdbcParameter();38 39         41              OdbcPermission(state);43     }

当然,我们也有oleDbFactory 类型,都是负责具体的数据库 *** 作。DbProvIDerFactory就是【抽象工厂】模式UML里面AbstractFactory类型。其他具体的工厂类型继承DbProvIDerFactory类型,这个结构很简单,我就不画图了。

五、总结

   终于写完了,写了3个小时,学习设计模式不能死学,要把握核心点和使用场景。关键点第一是,面向对象设计模式的基本原则,有了原则,考虑问题就不会跑偏,然后再仔细把握每种模式的使用场景和要解决的问题,多写写代码,多看看Net的类库,它是最好的教材。

总结

以上是内存溢出为你收集整理的C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】全部内容,希望文章能够帮你解决C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1213980.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存