(五)抽象工厂模式详解 (一)

2014-11-24 10:41:11 · 作者: · 浏览: 0

前两章我们已经讨论了两种有关工厂的模式,今天我们来看最后一种与工厂相关的模式,抽象工厂模式。

抽象工厂模式算是工厂相关模式的终极形态,如果各位完全理解了上一章的工厂方法模式,那么抽象工厂模式就很好理解了。它与工厂方法唯一的区别就是工厂的接口里是一系列创造抽象产品的方法,而不再是一个,而相应的,抽象产品也不再是一个了,而是一系列相关的产品。这其实是工厂方法模式的一种扩展不是吗

通常意义来我们谈到扩展,通常有两种方式可以扩展一个接口或者类,就是继承和组合。

通常情况下,我们推荐使用组合扩展一个现有的类或接口,但这并非绝对,如果你扩展的子类或子接口与现有的类或接口明显是“是一个(is a)”的关系,也就是继承的关系,那么使用继承可以获得更多的好处。

上一章我们介绍了iterable接口,它可以制作iterator,iterator方法是一个工厂方法,用于让子类制作一系列的iterator,不过java集合框架一般都将iterator的实现作为内部类出现,所以我们从未见过LZ上章提到的ListIterator和KeyIterator的实现类,但它们确实存在于JAVA的集合框架,并且它们的实现类被封装在相应的抽象类或者具体的容器实现类中。

oracle公司为何不让我们看到这些iterator的实现类呢?其实原因很简单,一是怕我们在写程序的时候依赖于这些iterator的实现类,二是这些迭代器的实现都要依赖于当前的容器实现,我们假设有一天JDK中的集合框架要升级,要替换掉某个iterator的实现,换做一种更快的迭代方式(假设存在这种方式),那么以前使用特定迭代器的程序可能就无法正常运行了。当然大部分的情况下,oracle不会将现有的类剔除,但是会加上@Deprecated注解,来标识这是一个过时的东西,不再推荐你使用。但就算是这样,一个缺点就是JDK升级以后,你享受不到JDK集合框架速度上的提升,除非你将所有你使用过具体的Iterator的地方全部手动替换掉。

上述大致描述了下抽象工厂模式的来源以及集合框架设计时对iterator处理方式的初衷,从中可以看出抽象工厂模式就是为了解决抽象产品不再是一个的时候的问题。因为不管是简单工厂,还是工厂方法,都有一个缺陷,那就是整个模式当中只能有一个抽象产品,所以直观的,你在工厂方法模式中再添加一个创造抽象产品的方法就是抽象工厂模式了,相应的当然还有添加一个抽象产品,还有一系列具体的该抽象产品的实现。

在集合框架里,有一个不太明显的抽象工厂模式,就是List接口,它在iterable的基础上,扩展了一个创建产品的方法,本次以List接口为例,我们来看看List接口的源码

[java]
package java.util;

public interface List extends Collection {

Iterator iterator();//一种产品

Object[] toArray();

T[] toArray(T[] a);

ListIterator listIterator();//另外一种产品

ListIterator listIterator(int index);

}

package java.util;

public interface List extends Collection {

Iterator iterator();//一种产品

Object[] toArray();

T[] toArray(T[] a);

ListIterator listIterator();//另外一种产品

ListIterator listIterator(int index);

}
LZ去掉了List接口中的很多方法,一是为了节省版面,另外是为了更清晰,我们主要关注iterator和listIterator方法,LZ在上面加了标注。

其中ListIterator是Iterator的子接口,但归根到底,它其实属于另外一种产品,为什么这么说呢,ListIterator不是Iterator的子接口吗,怎么能算是另外一种产品呢?这是因为我们listIterator方法的返回类型是ListIterator,而不是Iterator,所以两者的功能是不同的,比如ListIterator还可以向前移动。

我们可以认为这两个方法产生的一个是只能向后移动的迭代器,一个是可以前后移动的迭代器,这算是两种产品。

这个设计可以看做是一个抽象工厂模式,List接口定义了两种生产不同产品的方法,这属于两个系列的产品,不过由于产品接口本身的继承关系,两者的实现类也会被做成继承的关系。下面给出上面提到的接口的UML图。


这个图看起来有点复杂(直线表示实现接口的含义,LZ加入了implements关键字说明),下面来解释一下在抽象工厂模式当中,上述几个类都代表的什么角色。

1.List,是抽象工厂的角色,它有两个制造产品的方法,iterator和listIterator。

2.ListIterator和Iterator都是抽象产品。其中ListIterator有两个实现类,分别是AbstractList.ListItr和LinkedList.ListItr。Iterator的实现类为AbstractList.Itr。

3.LinkedList是其中一个具体的工厂类,实现抽象工厂List,它制造的两个具体产品分别是LinkedList.ListItr和AbstractList.Itr。

4.同样的,ArrayList也是一个具体的工厂类,实现抽象工厂List,它制造的两个具体产品分别是AbstractList.ListItr和AbstractList.Itr。

结合上一章Iterable接口是List的父接口,所以它只负责一个产品Iterator的制造,所以是工厂方法模式,而List接口扩展了Iterable接口,又添加了一个制造产品的方法,所以即成为抽象工厂模式。

下面LZ给出最一般化的抽象工厂模式类图,LZ直接拿来百度上面的标准类图,方便各位与上面的类图对比。

LZ下面给出上述两个类图的对应关系:

1.Creator=List

2.ConcreteCreator1=ArrayList

3.ConcreteCreator2=LinkedList

4.ProductA=Iterator