寫在前面的話
在上一篇Android源碼中的靜態工廠方法中我門一起研究了工廠模式三兄弟中最簡單的靜態工廠方法。今天我們來一起看看三兄弟中的老二————工廠方法模式,以及它在Android源碼中的體現。
今天我們先來模擬一個場景,把這三兄弟拎出來給大家瞅瞅,以免以後大家認錯。
- 今天我們決定進軍手機行業,手機名字叫做aPhone。我們要做一個aPhone1的樣品。————我們的直接new一個aPhone1對象就好了
- 我們的aPhone1賣的巨火,擋都擋不住,我們要出aPhone2、aPhone3、aPhone4等等一系列手機。————我們可以通過簡單工廠方法來生產手機(老三)
- 我們的aPhone系列手機配置比較高,考慮到市場上對低端產品的需求,我們要做aPhoneNote系列手機。————我們可以通過工廠方法模式來生產(老二)
- 由於我們aPhone6系列手機的屏幕生產時出現了問題,導致手機壽命降低,給公司造成了很大的損失。現在我們要從零件方面來把控產品質量,屏幕、電池、主板等零件的質量我們都要做質檢。————我們可以通過抽象工廠來生產(老大)
這就是工廠三兄弟。
工廠方法模式
定義
工廠方法模式是類的創建模式,又叫做虛擬構造子(Virtual Constructor)模式或者多態性工廠(Polymorphic Factory)模式。
工廠方法模式的用意是定義一個創建產品對象的工廠接口,將實際創建工作推遲到子類中。
結構
工廠方法模式所涉及到的角色:
- Product(抽象產品角色):它是具體產品繼承的父類或者是實現的接口。在java中一般有抽象類或者接口來實現。
- ConcreteProduct(具體產品角色):具體工廠角色所創建的對象就是此角色的實例。在java中由具體的類來實現。
- Factory(抽象工廠角色):這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。
- ConcreteFactory(具體工廠角色):它含有和具體業務邏輯有關的代碼。由應用程序調用以創建對應的具體產品的對象。
實現
我們用我們上邊手機的例子來實現。
抽象產品角色
abstract class APhone {
//所有產品類的公共業務方法
public void methodSame() {
//公共方法的實現
}
//聲明抽象業務方法
public abstract void methodDiff();
}
具體產品角色類,這裏我們只說一類,比如我們的aPhoneNote系列手機
class APhoneNote1 extends APhone {
//實現業務方法
public void methodDiff() {
//業務方法的實現
}
}
抽象工廠角色
abstract class Factory {
//靜態工廠方法
public abstract APhone createProduct(String arg);
}
具體工廠角色,這裏我們只說生產aPhoneNote系列手機的工廠
class ConcreteFactory {
//靜態工廠方法
public APhone createProduct(String arg) {
APhone aPhoneNote = null;
if (arg.equalsIgnoreCase("1")) {
aPhoneNote = new APhoneNote1();
//初始化設置product
}
else if (arg.equalsIgnoreCase("2)) {
aPhoneNote = new APhoneNote2();
//初始化設置product
}
return aPhoneNote;
}
}
使用場景
需要創建複雜對象
需要靈活、可擴展的框架,且具體類型不多
Android中工廠方法模式的應用
Java中的類集框架
我們在開發中會用到很多數據結構,比如ArrayList,HashMap等。我們先來看下Java中Collection部分的類集框架的簡要UML圖。
我們知道Iterator是迭代器,用來遍歷一個集合中的元素。而不同的數據結構遍歷的方式是不一樣的,所以迭代器的實現也是不同的。使用工廠方法模式將迭代器的具體類型延遲到具體容器類中,比較靈活,容易擴展。
List和Set繼承自Collection接口,Collection接口繼承於Iterable接口。
public interface Iterable<T> {
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();
//省略部分代碼
}
所以List和Set接口也會繼承該方法。然後我們常用的兩個間接實現類ArrayList和HashSet中的iterator方法就給我們構造並返回了一個迭代器對象。
我們找到ArrayList類,查看iterator方法的實現。
@Override
public Iterator<E> iterator() {
return new ArrayListIterator();
}
ArrayListIterator類型定義如下:
private class ArrayListIterator implements Iterator<E> {
/** Number of elements remaining in this iteration */
private int remaining = size;
/** Index of element that remove() would remove, or -1 if no such elt */
private int removalIndex = -1;
/** The expected modCount value */
private int expectedModCount = modCount;
public boolean hasNext() {
return remaining != 0;
}
@SuppressWarnings("unchecked") public E next() {
ArrayList<E> ourList = ArrayList.this;
int rem = remaining;
if (ourList.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (rem == 0) {
throw new NoSuchElementException();
}
remaining = rem - 1;
return (E) ourList.array[removalIndex = ourList.size - rem];
}
public void remove() {
Object[] a = array;
int removalIdx = removalIndex;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (removalIdx < 0) {
throw new IllegalStateException();
}
System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
a[--size] = null; // Prevent memory leak
removalIndex = -1;
expectedModCount = ++modCount;
}
}
我們看到這個類實現了Iterator接口,接口的定義如下:
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
我們基本的結構也分析完了,接下來對號入座,看一看具體是如何實現工廠方法模式的。
Iterator————>Product;ArrayListIteratorr————>ConcreteProduct。
Iterable/List————>Factory;ArrayList————>ConcreteFactory。
工廠方法使一個類的實例化延遲到子類,對應着將迭代器Iterator的創建從List延遲到了ArrayList。這就是工廠方法模式。
瞎總結
看是看完了,但是,總要給我們一個這麼做的理由吧?
個人認爲,這樣設計使得我們的代碼結構變得更清晰,同是比較容易擴展,因爲我們已經定義好了一套標準,只要按照規矩來就好了。
同時耦合度降低了,高層模塊只需要知道產品的抽象類,無所謂具體怎麼實現這個產品。