定义:

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

结构图:

  抽象工厂模式、反射_客户端

  

  AbstractProductA和AbstractProductB是两个抽象产品,有两种不同的实现。(User、Department)

  ProductA1、ProductA2、ProductB1、ProductB2就是对两个抽象产品的具体分类实现。(AccessUser、SqlserverUser、AccessDepartment、SqlserverDepartment)

  Ifactory,抽象工厂接口。包含所有产品创建的抽象方法。

  ConcreteFactory1、ConcreteFactory2,具体的工厂。

  通常,运行时刻,创建一个ConcreteFactory类的实例,这个具体工厂再创建具有特定实现的产品对象。即,为创建不同的产品对象,客户端使用不同的具体工厂。

示例:

  用户与数据库交互的解耦。(即,业务逻辑与数据访问解耦)

  抽象工厂模式、反射_解耦_02

  进阶:添加访问数据库的用户。

  抽象工厂模式、反射_解耦_03

  抽象工厂模式、反射_抽象工厂_04

  抽象工厂模式、反射_sql_05

优点:

  易于交换产品系列。由于具体工厂类在一个应用程序中只需要再初始化的时候出现一次。使得改变一个应用的具体工厂变得非常容易。只需要改变具体工厂即可使用不同的产品配置。(不能防止需求的更改,则让改动变得最小)

  让具体的创建示例过程与客户端分离。客户端是通过他们的抽象接口操纵实例。产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。(客户端只认识IUser、IDepartment,对于用SQL Server实现还是Access实现就不知道了)

  开放-封闭原则、依赖倒转原则

缺点:

  增加用户类(产品类)的时候,需要修改的地方多。(添加类:产品抽象类、产品实现类(多种方式对应多个类);添加方法:抽象工厂接口、抽象实现类(实现方式对应多个类))

  修改实现方式的时候,n个产品调用实现同一实现方式时,需要修改n次。

  编程是门艺术,这样大批量的改动,显然是非常丑陋的做法。

优化:  

  优化一:

  简单工厂。抛弃抽象工厂类、具体工厂类,用DataAccess类来取而代之。当修改工厂方式时,只需修改db的值即可。这样客户端不需要出现工厂方式,打到解耦的目的。

  抽象工厂模式、反射_抽象工厂_06

  抽象工厂模式、反射_抽象工厂_07

  缺点:如果需要增加工厂方式。抽象工厂增加一个具体工厂类就可以了。现在,需要在DataAccess类中每个方法添加case

 

  优化二:

  依赖注入,反射:修改,增加都达到了解耦的目的。

  反射格式:

  抽象工厂模式、反射_抽象工厂_08

  抽象工厂模式、反射_sql_09

   将SqlserverUser用变量来处理,达到灵活更换的目的。之前实例化都是写死在程序里的,而现在用了反射就可以用字符串来实例化对象,变量是可以更换的。更准确的说,将程序由编译时转为运行时。

  结构图如方式一。

  抽象工厂模式、反射_sql_10

  优点:

  修改工厂方式,只需修改db即可,达到对于修改尽量关闭的目的。增加工厂方式,只需在对应产品类添加具体实现类,并在DataAccess添加创建产品的方法即可。

  反射+抽象工厂模式,解决了数据库访问时的可维护、可扩展的问题。

  缺点:更换工厂方式时,还是需要改程序,重新编译。

  总结:switch或if是程序中的好东西,但在应对变化上,却显得老态龙钟。反射技术的确可以很好地解决他们难以定对变化,难以维护、扩展的诟病。

 

  优化三:

  反射+配置文件:优化修改工厂方式时,需重新编译。

   抽象工厂模式、反射_解耦_11

  抽象工厂模式、反射_工厂类_12

  

扩展:

  工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。

  所有在用简单工厂的地方,都可以考虑用反射技术来去除switch或if,解除分支判断带来的耦合。