意图

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

适用性

  在以下情况可以使用 Abstract Factory模式

    一个系统要独立于它的产品的创建、组合和表示时。
    • 一个系统要由多个产品系列中的一个来配置时。
    • 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
    • 当你提供一个产品类库,而只想显示它们的接口而不是实现时。

结构

  模式结构图如下所示:

 

 

  Creator: 声明一个创建抽象产品对象的操作接口。

  ConcreteCreator:(ConcreteCreator1,ConcreteCreator2):实现创建具体产品对象的操作。

  Product(ProductA,ProductB):为一类产品对象声明一个接口。

  ConcreteProduct(ProductA1,ProductA2,ProductB1,ProductB2):定义一个将被相应的具体工厂创建的产品对象。实现 Product接口。

  Client:仅使用由CreatorProduct类声明的接口。


 

协作

  通常在运行时刻创建一个 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,所以抽象工厂模式就是工厂方法模式添加了抽象产品所演变而来的。

 

posted on 2016-11-11 11:21  Achris  阅读(272)  评论(0编辑  收藏  举报