定义:
抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
结构图:
AbstractProductA和AbstractProductB是两个抽象产品,有两种不同的实现。(User、Department)
ProductA1、ProductA2、ProductB1、ProductB2就是对两个抽象产品的具体分类实现。(AccessUser、SqlserverUser、AccessDepartment、SqlserverDepartment)
Ifactory,抽象工厂接口。包含所有产品创建的抽象方法。
ConcreteFactory1、ConcreteFactory2,具体的工厂。
通常,运行时刻,创建一个ConcreteFactory类的实例,这个具体工厂再创建具有特定实现的产品对象。即,为创建不同的产品对象,客户端使用不同的具体工厂。
示例:
用户与数据库交互的解耦。(即,业务逻辑与数据访问解耦)
进阶:添加访问数据库的用户。
优点:
易于交换产品系列。由于具体工厂类在一个应用程序中只需要再初始化的时候出现一次。使得改变一个应用的具体工厂变得非常容易。只需要改变具体工厂即可使用不同的产品配置。(不能防止需求的更改,则让改动变得最小)
让具体的创建示例过程与客户端分离。客户端是通过他们的抽象接口操纵实例。产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。(客户端只认识IUser、IDepartment,对于用SQL Server实现还是Access实现就不知道了)
开放-封闭原则、依赖倒转原则
缺点:
增加用户类(产品类)的时候,需要修改的地方多。(添加类:产品抽象类、产品实现类(多种方式对应多个类);添加方法:抽象工厂接口、抽象实现类(实现方式对应多个类))
修改实现方式的时候,n个产品调用实现同一实现方式时,需要修改n次。
编程是门艺术,这样大批量的改动,显然是非常丑陋的做法。
优化:
优化一:
简单工厂。抛弃抽象工厂类、具体工厂类,用DataAccess类来取而代之。当修改工厂方式时,只需修改db的值即可。这样客户端不需要出现工厂方式,打到解耦的目的。
缺点:如果需要增加工厂方式。抽象工厂增加一个具体工厂类就可以了。现在,需要在DataAccess类中每个方法添加case
优化二:
依赖注入,反射:修改,增加都达到了解耦的目的。
反射格式:
将SqlserverUser用变量来处理,达到灵活更换的目的。之前实例化都是写死在程序里的,而现在用了反射就可以用字符串来实例化对象,变量是可以更换的。更准确的说,将程序由编译时转为运行时。
结构图如方式一。
优点:
修改工厂方式,只需修改db即可,达到对于修改尽量关闭的目的。增加工厂方式,只需在对应产品类添加具体实现类,并在DataAccess添加创建产品的方法即可。
反射+抽象工厂模式,解决了数据库访问时的可维护、可扩展的问题。
缺点:更换工厂方式时,还是需要改程序,重新编译。
总结:switch或if是程序中的好东西,但在应对变化上,却显得老态龙钟。反射技术的确可以很好地解决他们难以定对变化,难以维护、扩展的诟病。
优化三:
反射+配置文件:优化修改工厂方式时,需重新编译。
扩展:
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。
所有在用简单工厂的地方,都可以考虑用反射技术来去除switch或if,解除分支判断带来的耦合。