首页 > 代码库 > 设计模式可复用面向对象软件设计基础之对象创建型模式—ABSTRACT FACTORY( 抽象工厂)
设计模式可复用面向对象软件设计基础之对象创建型模式—ABSTRACT FACTORY( 抽象工厂)
意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
适用性
在以下情况可以使用 Abstract Factory模式
? 一个系统要独立于它的产品的创建、组合和表示时。
? 一个系统要由多个产品系列中的一个来配置时。
? 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
? 当你提供一个产品类库,而只想显示它们的接口而不是实现时。
结构
模式结构图如下所示:
Creator: 声明一个创建抽象产品对象的操作接口。
ConcreteCreator:(ConcreteCreator1,ConcreteCreator2):实现创建具体产品对象的操作。
Product(ProductA,ProductB):为一类产品对象声明一个接口。
ConcreteProduct(ProductA1,ProductA2,ProductB1,ProductB2):定义一个将被相应的具体工厂创建的产品对象。实现 Product接口。
Client:仅使用由Creator和Product类声明的接口。
协作
通常在运行时刻创建一个 ConcreteFactroy类的实例。这一具体的工厂创建具有特定实现的产品对象。为创建不同的产品对象,客户应使用不同的具体工厂。
AbstractFactory将产品对象的创建延迟到它的 ConcreteFactroy子类。
效 果
AbstractFactory模式有下面的一些优点和缺点:
1) 它分离了具体的类 Abstract Factory模式帮助你控制一个应用创建的对象的类。因为一个工厂封装创建产品对象的责任和过程,它将客户与类的实现分离。客户通过它们的抽象接口操纵实例。产品的类名也在具体工厂的实现中被分离;它们不出现在客户代码中。
2) 它使得易于交换产品系列 一个具体工厂类在一个应用中仅出现一次—即在它初始化的时候。这使得改变一个应用的具体工厂变得很容易。它只需改变具体的工厂即可使用不同的产品配置,这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系列会立刻改变。
3) 它有利于产品的一致性 当一个系列中的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要。而 AbstractFactory很容易实现这一点。
4) 难 以 支 持 新 种 类 的 产 品 难以扩展抽象工厂以生产新种类的产品。这是因为AbstractFactory接口确定了可以被创建的产品集合。 支持新种类的产品就需要扩展该工厂接口,这将涉及AbstractFactory类及其所有子类的改变。我们会在实现一节讨论这个问题的一个解决办法。
实 现
下面是实现Abstract Factor模式的一些有用技术:
1) 将工厂作为单件 一个应用中一般每个产品系列只需一个 ConcreteFactroy的实例。因此工厂通常最好实现为一个 Singleton。
2) 创建产品 AbstractFactory仅声明一个创建产品的接口,真正创建产品是由 ConcreteProduct子类实现的。最通常的一个办法是为每一个产品定义一个工厂方法。一个具体的工厂将为每个产品重定义该工厂方法以指定产品。虽然
这样的实现很简单,但它却要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。
如果有多个可能的产品系列,具体工厂也可以使用 Prototype模式来实现。具体工厂使用产品系列中每一个产品的原型实例来初始化,且它通过复制它的原型来创建新的产品。在基于原型的方法中,使得不是每个新的产品系列都需要一个新的具体工厂类。
JAVA集合框架中抽象模式的应用。
下面部分摘录自大神左潇龙博客抽象工厂模式详解
在集合框架里,有一个不太明显的抽象工厂模式,就是List接口,它在iterable的基础上,扩展了一个创建产品的方法,本次以List接口为例,我们来看看List接口的源码。
package java.util; public interface List<E> extends Collection<E> { Iterator<E> iterator();//一种产品 Object[] toArray(); <T> T[] toArray(T[] a); ListIterator<E> listIterator();//另外一种产品 ListIterator<E> listIterator(int index); }
LZ去掉了List接口中的很多方法,一是为了节省版面,另外是为了更清晰,我们主要关注iterator和listIterator方法,LZ在上面加了标注。
其中ListIterator是Iterator的子接口,但归根到底,它其实属于另外一种产品,为什么这么说呢,ListIterator不是Iterator的子接口吗,怎么能算是另外一种产品呢?这是因为我们listIterator方法的返回类型是ListIterator,而不是Iterator,所以两者的功能是不同的,比如ListIterator还可以向前移动。
我们可以认为这两个方法产生的一个是只能向后移动的迭代器,一个是可以前后移动的迭代器,这算是两种产品,相当于上面的ProductA和ProductB。
这个设计可以看做是一个抽象工厂模式,List接口定义了两种生产不同产品的方法,这属于两个系列的产品,不过由于产品接口本身的继承关系,两者的实现类也会被做成继承的关系。下面给出上面提到的接口的UML图。
这个图看起来有点复杂,各位可以和上面标准的抽象工厂模式类图对比一下,下面LZ来解释一下在抽象工厂模式当中,上述几个类都代表的什么角色。
1.List,是抽象工厂的角色,它有两个制造产品的方法,iterator和listIterator,相当于Creator。
2.ListIterator和Iterator都是抽象产品,相当于ProductA和ProductB。其中ListIterator有两个实现类,分别是AbstractList.ListItr和LinkedList.ListItr,相当于ProductA1和ProductA2。Iterator的实现类为AbstractList.Itr,相当于ProductB1,但是没有B2。
3.LinkedList是其中一个具体的工厂类,相当于ConcreteCreator1,实现抽象工厂List,它制造的两个具体产品分别是LinkedList.ListItr和AbstractList.Itr。
4.同样的,ArrayList也是一个具体的工厂类,相当于ConcreteCreator2,实现抽象工厂List,它制造的两个具体产品分别是AbstractList.ListItr和AbstractList.Itr。
我们来分析一下工厂方法模式和抽象工厂模式二者的关系。
Iterable接口是List的父接口,所以它只负责一个产品Iterator的制造,所以是工厂方法模式,而List接口扩展了Iterable接口,又添加了一个制造产品的方法,即又添加了一个系列的产品,所以就成为了抽象工厂模式。
LZ下面给出上述两个类图的对应关系,会让各位看的更加清晰:
1.Creator=List
2.ConcreteCreator1=ArrayList
3.ConcreteCreator2=LinkedList
4.ProductA=Iterator
5.ProductB=ListIterator
6.ProductA1=AbstractList.Itr
7.ProductA2=无(具体的A产品2在第一个类图中是没有的,但这并不影响整个体系)
8.ProductB1=AbstractList.ListItr
9.ProductB2=LinkedList.ListItr
ArrayList和LinkedList分别是List接口的两种实现,前者是基于数组操作,后者是基于链表。两者都可以产生Iterator和ListIterator,而Iterator的实现都是在AbstractList中实现的,是一样的处理方式,而对于ListIterator的实现却不相同,AbstractList.ListItr是基于数组的操作,LinkedList.ListItr是基于链表的操作方式。
所以抽象工厂模式一般是为了处理抽象产品多于一个的问题,而且这些产品多数情况下是有关系的,像上述JAVA集合框架的例子当中,Iterator和ListIterator就是继承的关系,大部分情况下,很少会使用抽象工厂模式去创造一批毫无关系的产品。
基于抽象工厂一旦定义,抽象产品的个数就已经固定,所以最好在抽象产品的个数不太会变化的情况下使用抽象工厂模式,当然,我们可以使用继承去弥补抽象工厂模式的这一不足,创造另外一个继承体系去扩展现有的框架。
下面LZ给出简单工厂模式,工厂方法模式一直到抽象工厂模式的演变过程,三者是由简到繁的关系。由于三者都已经详细的解释过,所以此处不再多做解释,留给各位读者自己思考它们的进化过程,首先LZ给出简单工厂的具体代码。
//抽象产品 interface Product{} //具体产品 class ProductA implements Product{} class ProductB implements Product{} //产品工厂(下一步就是它的进化,就变成了工厂方法模式) public class ProductFactory { private ProductFactory(){} public static Product getProduct(String productName){ if (productName.equals("A")) { return new ProductA(); }else if (productName.equals("B")) { return new ProductB(); }else { return null; } } }
LZ在上面加了简单的注释,下面LZ给出工厂方法模式的代码,注意,前面有关产品的类和接口是不变的。
//抽象产品 interface Product{} //具体产品 class ProductA implements Product{} class ProductB implements Product{} //将简单工厂中的工厂给抽象成接口 interface Factory{ Product getProduct(); } //具体的工厂A,创造产品A class FactoryA implements Factory{ public Product getProduct() { return new ProductA(); } } //具体的工厂B,创造产品B class FactoryB implements Factory{ public Product getProduct() { return new ProductB(); } }
可以看到,产品部分并没有变化,只是将简单工厂中的工厂类抽象成接口,并给相应产品添加相应的工厂类,就进化成了工厂方法模式。下面我们再看工厂方法如何进化成抽象工厂模式。
//抽象产品 interface Product{} //具体产品 class ProductA implements Product{} class ProductB implements Product{} //多了一个抽象产品1 interface Product1{} //具体产品1 class Product1A implements Product1{} class Product1B implements Product1{} //原有的工厂方法模式的工厂里添加一个方法 interface Factory{ Product getProduct(); //添加另外一个产品族的创造方法 Product1 getProduct1(); } //具体的工厂A,创造产品A class FactoryA implements Factory{ public Product getProduct() { return new ProductA(); } //添加相应的实现 public Product1 getProduct1() { return new Product1A(); } } //具体的工厂B,创造产品B class FactoryB implements Factory{ public Product getProduct() { return new ProductB(); } //添加相应的实现 public Product1 getProduct1() { return new Product1B(); } }
与工厂方法对比下就发现,多了一个产品系列叫Product1,工厂接口里多了一个方法,叫getProduct1,所以抽象工厂模式就是工厂方法模式添加了抽象产品所演变而来的。
设计模式可复用面向对象软件设计基础之对象创建型模式—ABSTRACT FACTORY( 抽象工厂)