设计模式之工厂方法模式及在源码中的应用

工厂方法

在任何需要生成复杂对象的地方,都可以使用工厂方法模式,复杂对象适合使用工厂方法模式,用 new 就可以完成创建的对象无需使用工厂方法模式。

优点:降低了对象之间的耦合度,工厂模式依赖于抽象的架构,其将实例化的任务交由子类去完成,有非常好的扩展性。
缺点:每次为工厂方法添加新的产品时就要编写一个新的产品类,同还要引入抽象层,必然会导致代码类结构的复杂化。

工厂方法模式的通用模式代码如下:

  1. 抽象工厂方法(核心),具体生产什么由子类去实现:

    1
    2
    3
    public abstract class Factory {
    public abstract Product createProduct();
    }
  2. 具体工厂类(实现了具体业务逻辑):

    1
    2
    3
    4
    5
    6
    7
    public class ConcreteFactory extends Factory{
    @Override
    public Product createProduct() {
    return new ConcreteProductA(); // 返回具体的产品对象
    //return new ConcreteProductB(); // 返回具体的产品对象
    }
    }
  3. 抽象产品类,由具体的产品类去实现:

    1
    2
    3
    public abstract class Product {
    public abstract void method();
    }
  4. 具体产品类(包含ConcreteProductA、ConcreteProductB等):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class ConcreteProductA extends Product {
    @Override
    public void method() {
    System.out.println("ConcreteProductA method");
    }
    }
    public class ConcreteProductB extends Product {
    @Override
    public void method() {
    System.out.println("ConcreteProductB method");
    }
    }
  5. 测试程序:

    1
    2
    3
    4
    5
    6
    @Test
    public void factoryTest() throws Exception {
    Factory factory = new ConcreteFactory();
    Product product = factory.createProduct();
    product.method();
    }

输出:ConcreteProductA method

这种方式比较常见,需要哪个就生产哪个,有时候还可以利用反射的方式更加简洁地来生产具体产品对象,此时,需要在工厂方法的参数列表中传入一个 Class 类来决定是哪一个产品类:

1
2
3
4
5
6
7
8
public abstract class Factory {
/**
* @param clz 产品对象类类型
* @param <T> 具体的产品对象
* @return
*/
public abstract <T extends Product> T createProduct(Class<T> clz);
}

对应的具体工厂类则通过反射获取类的实例即可:

1
2
3
4
5
6
7
8
9
10
11
12
public class ConcreteFactory extends Factory{
@Override
public <T extends Product> T createProduct(Class<T> clz) {
Product p = null;
try {
p = (Product) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) p;
}
}

再看一下测试代码的实现:

1
2
3
4
5
6
7
8
@Test
public void factoryTest() throws Exception {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct(ConcreteProductA.class);
product.method();
Product product = factory.createProduct(ConcreteProductA.class);
product.method();
}

输出:
ConcreteProductA method
ConcreteProductB method

需要哪个类的对象传入哪一个类即可,这种方法比较简洁、动态。如果不喜欢这一种,也可以尝试为每一个产品都定义一个具体的工厂,各司其职,像拥有多个工厂的方式我们称为多工厂方法模式,同样当我们的工厂类只有一个的时候,我们还可以简化掉抽象类,只需要将对应的工厂方法给为静态方法即可:

1
2
3
4
5
public class Factory {
public static Product createProduct() {
return new ConcreteProductA();
}
}

源码中的应用

工厂方法模式应用很广泛,开发中使用到的数据结构中就隐藏着对工厂方法模式的应用,例如 List、Set,List、Set 继承自 Collection 接口,而 Collection 接口继承于 Iterable 接口:

1
2
3
public interface Iterable<T> {
Iterator<T> iterator();
}

这意味着 List、Set 接口也会继承 iterator() 方法,下面以 ArrayList 为例进行分析:
ArrayList 中 iterator() 方法的实现就是构造并返回一个迭代器对象:

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
45
46
47
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
public Iterator<E> iterator() {
return new Itr();
}
// 迭代器
private class Itr implements Iterator<E> {
protected int limit = java.util.ArrayList.this.size;
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor < limit;
}
@SuppressWarnings("unchecked")
public E next() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
int i = cursor;
if (i >= limit)
throw new NoSuchElementException();
Object[] elementData = java.util.ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
try {
java.util.ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
limit--;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
// 代码省略
}
// 代码省略
}

其中的 iterator() 方法其实就相当于一个工厂方法,专为 new 对象而生,构造并返回一个具体的迭代器。

其实Android中对工厂方法模式的应用更多,先看如下代码:

1
2
3
4
5
6
7
public class AActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(new LinearLayout(this));
}
}

实际上,onCreate方法就相当于一个工厂方法,因为LinearLayout是一个ViewGroup,而ViewGroup又继承于View,简单地说,所有控件都是View的子类。在AActivity的onCreate方法中构造一个View对象,并设置为当前的ContentView返回给framework处理,如果现在又有一个BActivity,这时又在onCreate方法中通过setContentView方法设置另外不同的View,这是不是一个工厂模式的结构呢,其实设计模式离我们非常近!!!