腊月的季节

设计模式之抽象工厂模式

应用场景

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
首先我们看一下百度百科对抽象工厂模式的图分析。
图片加载中
大致流程是这样,创建一个接口creator,一组相关或者相互依赖的对象就是ProductA和ProductB以及它们具体的实现类,而上面又提到说不是返回的具体的类,所以我们返回的应该是接口或者抽象类,那么上述类图当中,则是指的ProductA和ProductB接口。

抽象工厂模式实例

首先给出我们的产品族,图的右半部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.liu.abstract1;

interface ProductA{
void methodA();
}
interface ProductB{
void methodB();
}
class ProductA1 implements ProductA{
@Override
public void methodA() {
// TODO Auto-generated method stub
System.out.println("产品A系列中1型号产品的方法");
}
}
class ProductA2 implements ProductA{
@Override
public void methodA() {
// TODO Auto-generated method stub
System.out.println("产品A系列中2型号产品的方法");
}
}
class ProductB1 implements ProductB{
public void methodB(){
System.out.println("产品B系列中1型号产品的方法");
}
}
class ProductB2 implements ProductB{
public void methodB(){
System.out.println("产品B系列中2型号产品的方法");
}
}

然后再给出创造产品的接口。

1
2
3
4
5
6
package com.liu.abstract1;

public interface Creator {
ProductA createProductA();
ProductB createProductB();
}

创建第一种产品库

1
2
3
4
5
6
7
8
9
10
package com.liu.abstract1;

public class ConcreteCreator1 implements Creator{
public ProductA createProductA(){
return new ProductA1();
}
public ProductB createProductB(){
return new ProductB1();
}
}

创建第二种产品库

1
2
3
4
5
6
7
8
9
10
package com.liu.abstract1;

public class ConcreteCreator2 implements Creator{
public ProductA createProductA(){
return new ProductA2();
}
public ProductB createProductB(){
return new ProductB2();
}
}

创建测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.liu.abstract1;

public class Client {
public static void main(String[] args) {
Creator creator=new ConcreteCreator1();
ProductA productA=creator.createProductA();
ProductB productB=creator.createProductB();
productA.methodA();
productB.methodB();
creator=new ConcreteCreator2();
productA=creator.createProductA();
productB=creator.createProductB();
productA.methodA();
productB.methodB();
}
}

输出结果

1
2
3
4
产品A系列中1型号产品的方法
产品B系列中1型号产品的方法
产品A系列中2型号产品的方法
产品B系列中2型号产品的方法

这就是一个简单的抽象工厂模式,一开始我看到抽象工厂模式,还以为他是要用抽象类和抽象方法,原来是我误解了,抽象工厂模式就是把原来的工厂糅合在一起,再变成几种工厂,随意组合。
这个相对比较简单。

深入理解

为了更深入的理解,我打算研究JDK源码,List接口源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);

}

这里面肯定是去掉了源码的很多方法,为了看着更简便。
其中ListIterator是Iterator的子接口,但归根到底,它其实属于另外一种产品,为什么这么说呢,ListIterator不是Iterator的子接口吗,怎么能算是另外一种产品呢?这是因为我们listIterator方法的返回类型是ListIterator,而不是Iterator,所以两者的功能是不同的,比如ListIterator还可以向前移动。
我们可以认为这两个方法产生的一个是只能向后移动的迭代器,一个是可以前后移动的迭代器,这算是两种产品,相当于上面的ProductA和ProductB。
这个设计可以看做是一个抽象工厂模式,List接口定义了两种生产不同产品的方法,这属于两个系列的产品,不过由于产品接口本身的继承关系,两者的实现类也会被做成继承的关系。
加载图片中
根据这个图,与上面的简单的对比一下。

  • List,是抽象工厂的角色,它有两个制造产品的方法,iterator和listIterator,相当于Creator。
  • ListItertor和Iterator都是抽象产品,相当于ProductA和ProductB。其中ListIterator有两个实现类,分别是AbstractList.ListItr和LinkedList.ListIter,相当于ProductA1和ProductA2.Iterator的实现类为AbstractList.Itr,相当于ProductB1,但是没有B2.
  • LinkedList是其中一个具体的工厂类,相当于ConcreteCreator1,实现抽象工厂List,它制造的两个具体产品分别是LinkedList.ListItr和AbstractList.Itr.
  • 同样的,ArrayList是一个具体的工厂类,相当于ConcreteCreator2,实现抽象工厂List,它制造的两个具体产品分别是AbstractList.ListItr和AbstractList.Itr。

    总结

    Iterable接口是List的父接口,所以它只负责一个产品Iterator的制造,所以是工厂方法模式,而List接口扩展了Iterable接口,又添加了一个制造产品的方法,即又添加了一个系列的产品,所以就成为了抽象工厂模式。
    给出上述两个类图的对应关系。
    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就是继承的关系,大部分情况下,很少会使用抽象工厂模式去创造一批毫无关系的产品。
    基于抽象工厂一旦定义,抽象产品的个数就已经固定,所以最好在抽象产品的个数不太会变化的情况下使用抽象工厂模式,当然,我们可以使用继承去弥补抽象工厂模式的这一不足,创造另外一个继承体系去扩展现有的框架。

    工厂模式总结

    简单工厂模式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //抽象产品  
    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;
    }
    }
    }

工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//抽象产品  
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();
}

}

抽象工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//抽象产品  
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,所以抽象工厂模式就是工厂方法模式添加了抽象产品所演变而来的。
1,首先从简单工厂进化到工厂方法,是因为工厂方法弥补了简单工厂对修改开放的弊端,即简单工厂违背了开闭原则。
2,从工厂方法进化到抽象工厂,是因为抽象工厂弥补了工厂方法只能创造一个系列的产品的弊端。

热评文章