抽象工厂模式

  理解抽象工厂模式包括要注意以下几个方面:

  1. 在工厂方法模式中我们描述了,抽象工厂创建抽象产品的过程,为什么不使用一个工厂类直接创建抽象产品呢?其实原因很简单:抽象产品角色是由Java 接口或者抽象Java 类实现的,而一个Java 接口或者抽象Java 类是不能实例化的。也就是说,一个工厂类是不能直接创建抽象产品的。
  2. 根据里氏代换原则(可详见《java编程思想》),任何接收父类型的地方,都应当能够接收子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例如下图所示。

抽象工厂模式的含义

  根据上面的图,我们可以对比一下工厂方法:工厂方法模式中,通过抽象工厂创建的是抽象产品,对于一个良好的工厂方法设计,一个抽象工厂创建的是一个抽象产品角色。因此需要多个抽象工厂,这种效果在实际应用上比较繁锁。而抽象工厂创建的工作下放到子类,而子类创建的也是产品的具体实类,如果这样,那么工厂类就很好的解决了工厂方法不足的一面。

  对于每个抽象产品都有多于一个的具体子类的话,工厂角色怎么知道实例化哪一个子类呢?如下图所示:

  理解了这三个步骤,就不难理解“抽象工厂”这个名字的来源了。“抽象”来自“抽象产品角色”,而“抽象工厂”就是抽象产品角色的工厂。在抽象工厂中,我们引进“产品族”的概念;如下图(相图)所示:

  对于产品族而言,从上图可知,每一个抽象产品具有三个具体产品;每一个具体工厂类对应一个产品族。在上面的相图中加入了具体工厂角色。可以看出,对应于每一个产品族都有一个具体工厂。而每一个具体工厂负责创建属于同一个产品族、但是分属于不同等级结构的产品。

抽象工厂模式结构

  抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广。假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品。下面就以一个示意性的系统为例,说明这个模式的结构。

 

  通过使用抽象工厂模式,可以处理具有相同(或者相似)等级结构的多个产品族中的产品对象创建问题。比如下面就是两个具有相同等级结构的产品族A 和产品等级结构B 的结构图。

  上图中,有两个产品族,每一个产品族具有两个具体产品。我们可以使用相图描述上面的结构,其中横坐标表示,每一个抽象产品下面具有的产品个数(2个);纵坐标表示,具有几个抽象产品(2个)。

  基于以上,在实际应用中,我们不难给出采用抽象工厂模式设计出的系统类图如下所示。

  从上图可以看出,抽象工厂模式涉及到以下的角色。

  • 抽象工厂(AbstractFactory)角色:担任这个角色的是工厂方法模式的核心,它是与应用系统的商业逻辑无关的。通常使用Java 接口或者抽象Java 类实现,而所有的具体工厂类必须实现这个Java 接口或继承这个抽象Java 类。
  • 具体工厂类(Conrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。通常使用具体Java 类实现这个角色。
  • 抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。通常使用Java 接口或者抽象Java 类实现这一角色。
  • 具体产品(Concrete Product)角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。通常使用具体Java 类实现这个角色。

抽象工厂的使用情况

  1. 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节。这对于所有形态的工厂模式都是重要的;
  2. 这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品;(上面这一条叫做抽象工厂模式的原始用意,在现代的应用中,抽象工厂模式的使用范围已经大大扩大了,不再要求系统只能消费某一个产品族了;因此读者可以不理会前面所提到的原始用意。)
  3. 同属于同一个产品族的产品是在一起使用的,这一约束必须要在系统的设计中体现出来;
  4. 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

  仔细思考一下,很多人都会问这样一个问题:为什么在第二条中说“系统只消费其中某一族的产品”呢?这实际上与抽象工厂模式的起源有关。我们在工厂方法中,作了应用示例,现在放到抽象工厂中,设计图如下所示:

 

抽象工厂中的增加

  1. 在产品等级结构的数目不变的情况下,增加新的产品族,就意味着在每一个产品等级结构中增加一个(或者多个)新的具体(或者抽象和具体)产品角色。由于工厂等级结构是与产品等级结构平行的登记机构,因此,当产品等级结构有所调整时,需要将工厂等级结构做相应的调整。现在产品等级结构中出现了新的元素,因此,需要向工厂等级结构中加入相应的新元素就可以了。换言之,设计师只需要向系统中加入新的具体工厂类就可以了,没有必要修改已有的工厂角色或者产品角色。因此,在系统中的产品族增加时,抽象工厂模式是支持“开-闭”原则的。

  2. 在产品族的数目不变的情况下,增加新的产品等级结构。换言之,所有的产品等级结构中的产品数目不会改变,但是现在多出一个与现有的产品等级结构平行的新的产品等级结构。要做到这一点,就需要修改所有的工厂角色,给每一个工厂类都增加一个新的工厂方法,而这显然是违背“开–闭”原则的。换言之,对于产品等级结构的增加,抽象工厂模式是不支持“开–闭”原则的。

  综合起来,我们可以知道,在已有的抽象产品中添加其具体产品,支持“开—闭原则”,然而在添加其抽象产品时,确不支持“开—闭”原则。抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,而不能为新的产品等级结构的增加提供这样的方便。

  注:个人认为,在基于抽象工厂的设计中,对于产品族和产品等级的设计与区分是很重要的,这往往对于初学者来说,容易混淆。对于具体工厂类,应按照相图中的产品族来定义。相图中的横坐标表示的是抽象产品角色。

posted @ 2016-07-12 10:09  简单爱_wxg  阅读(322)  评论(0编辑  收藏  举报