设计模式--抽象工厂

创建型–抽象工厂(Abstract Factory)

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

抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来,而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大的不同。

模式说明

要创建一系列的产品对象,而且这一系列对象是构建新对象所需要的组成部分,也就是这一系列被创建的对象相互之间是有约束的。
解决此类问题的一个解决方案就是抽象工厂模式,在这个模式里面,会定义一个抽象工厂,在里面虚拟的创建客户端需要的这一系列对象,所谓虚拟的就是定义创建这些对象的抽象方法,而不去真的实现,然后由具体的抽象工厂的子类来提供这一些列对象的创建。这样就可以为同一个抽象工厂提供很多不同的实现,那么创建的这一系列对象也就不一样了,也就是说,抽象工厂在这里起到了一个约束的作用,并提供所有子类的一个统一外观,来让客户端使用

类图

在这里插入图片描述

实现

抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory中的createProductA()createProductB()方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。
至于创建对象的家族这一概念是在Client体现,Client要通过AbstractFactory同时调用两个方法来创建两个对象,在这里这两个对象就有很大的相关性,client需要同时创建出这两个对象。
从高层次来看,抽象工厂使用了组合,即Client组合了AbstractFactory,而工厂方法模式使用了继承。
在这里插入图片描述

在这里插入图片描述

进一步理解

模式的功能

抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口,这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法。
从某种意义上看,抽象工厂其实就是一个产品系列,或者产品簇

实现成接口

AbstractFactory在Java中通常实现成为接口,而不是抽象类,如果需要为这个产品簇提供公共的功能,也可以将其实现成为抽象类,但是一般不这么做。

使用工厂方法

AbstractFactory定义了创建产品所需要的接口,具体的实现是在实现类里面,通常在实现类里面就需要选择多种更具体的实现,所以AbstractFactory定义的创建产品的方法可以看成是工厂方法,而这些工厂方法的具体实现就延迟到了具体的工厂里面,也就是使用工厂方法来实现抽象工厂

切换产品簇

切换一个产品簇的时候,只需要提供不同的抽象工厂实现就好了,也就是说现在是以产品簇做一个整体被切换。

抽象工厂模式的调用顺序示意图

在这里插入图片描述

可扩展的工厂

如果想要在产品簇中新增加一种产品,那么就需要在抽象工厂里面添加一类方法,当抽象工厂发生变化,所有具体工厂实现都要发生变化,这样非常的不灵活。
现在有一种相对灵活但是不太安全的改进方式来解决这个问题:抽象工厂里面不需要定义那么多的方法,定义一个方法就可以了,给这个方法设置一个参数,通过这个参数来判断具体创建什么产品对象;由于只有一个方法,在返回类型上就不能是具体的某个产品类型了,可以直接使用Object类型。
但是在创建产品对象返回来过后,需要成为具体的对象,需要进行强转,那么就有可能会发生错误,因此这种实现方式的一个潜在缺点就是不太安全。

抽象工厂与DAO

DAO

数据访问对象。DAO是JEE中的一个标准模式,通过它来解决访问数据对象所面临的一系列问题,比如:数据源不同、存储类型不同、访问方式不同、供应商不同、版本不同等等,这些不同会造成访问数据的实现上的差别很大。
但是对于需要进行数据访问的逻辑层而言,面对这么多的不同,并不想处理这么多的差异,他希望能以一个统一的方式来访问数据,此时系统结构如图所示:
在这里插入图片描述
DAO需要抽象和封装所有对数据的访问,承担和数据库的交互的职责,所以,访问数据所面临的的所有问题,都需要DAO在内部来自行解决。

DAO与抽象工厂

在实现DAO模式的时候,最常见的实现策略就是使用工厂的策略,而且多事抽象工厂模式来实现的。

DAO的工厂实现策略

采用工厂方法模式

如果业务比较简单,而且对数据的操作是固定的,比如就是操作数据库,不管订单的业务如何变化,底层数据存储都是一样的,那么这种情况下,可以采用工厂方法模式。
在这里插入图片描述

采用抽象工厂模式

实际上更多的时候,DAO底层存储方式是不固定的,DAO通常会支持多种存储实现方式,具体使用哪一种存储方式可能是由应用动态决定的,或者是通过配置来指定。对于这种情况,一般采用抽象工厂模式来实现DAO。
在这里插入图片描述

抽象工厂模式的优缺点

  1. 分离接口和实现
    客户端使用抽象工厂来创建需要的对象,而客户端并不知道具体的实现是谁,客户端只是面向产品的接口编程而已,也就是说,客户端从具体的产品中实现解耦
  2. 使得切换产品簇变得容易
    因为一个具体的工厂实现代表的是一个产品簇,客户端选择不同的工厂实现,就相当于是在切换不同的产品簇。
  3. 不太容易扩展新产品
    如果需要给整个产品簇添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。使用可以扩展工厂的方式来解决这个问题,但是又不够安全。
  4. 容易造成类层次复杂
    在使用抽象工厂模式的时候,如果需要选择的层次过多,那么会造成整个类层次变得复杂。
    举个例子来说,就比如前面讲到的那个DAO的示例,现在这个DAO只有一个选择的层次,也就是选择一下是使用关系型数据库来实现,还是用Xml来实现。现在考虑这样一种情况,如果关系型数据库实现里面又分成几种,比如:基于Oracle的实现,基于SqlServer的实现,基于MySql的实现等等。
    这个时候客户端就需要一层一层选择,也就是整个抽象工厂的实现也需要分出层次来,每一层负责一种选择,也就是一层屏蔽一种变化,这样很容易造成复杂的类层次结构

进一步理解

1. 抽象工厂的本质
抽象工厂模式的本质:选择产品簇的实现
2. 何时选择抽象工厂模式
(1)如果希望一个系统独立于它的产品的创建,组合和表示的时候,换句话说,希望一个系统只是知道产品的接口,而不关心实现的时候。
(2)如果一个系统要由多个产品系列中的一个来配置的时候,换句话说,就是可以动态的切换产品簇的时候。
(3)如果要强调一系列相关产品的接口,以便联合使用它们的时候。
3. 抽象工厂模式和工厂方法模式
这两个模式既有区别又有联系,可以组合使用。
工厂方法是选择单个产品的实现,虽然一个类里面可以有很多个工厂方法,但是这些方法之间一般是没有联系的,即使看起来像有联系。
但是抽象工厂着重的就是为一个产品簇选择实现,定义在抽象工厂里面的方法通常是有联系的,他们都是产品的某一部分或者是相互依赖的。如果抽象工厂里面只定义一个方法,直接创建产品,那么就退化为工厂方法了。
抽象工厂可以退化为工厂方法,工厂方法又可以退化为简单工厂
在抽象工厂的实现中,还可以使用工厂方法来提供抽象工厂的具体实现,也就是说他们可以组合使用。
4. 抽象工厂和单例模式
这两个模式可以组合使用。
在抽象工厂模式里面,具体的工厂的实现,在整个应用中,通常一个产品系列只需要一个实例就可以了,因此可以把具体的工厂实现为单例。
感谢并参考:
https://www.jianshu.com/p/e873855e88a0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值