Java 設計模式情景分析——工廠方法模式
工廠方法模式(Factory Pattern),是建立型設計模式之一。其在我們平時開發中應用很廣泛,如 Android 中的 Activity 裡的各個生命週期方法,以 onCreate 為例,它就可以看作是一個工廠方法,我們在其中可以構造我們的 View 並通過 setContentView 返回 framework 處理等。
定義:定義一個用於建立物件的介面,讓子類決定例項化哪個類。
1.工廠方法模式的使用情景
在任何需要生成複雜物件的地方,都可以使用工廠方法模式,複雜物件適合使用工廠方法模式,用 new 就可以完成建立的物件無需使用工廠方法模式。
2.程式中使用工廠方法模式的優缺點
- | 工廠方法模式 |
---|---|
優點 | 降低了物件之間的耦合度,工廠模式依賴於抽象的架構,其將例項化的任務交由子類去完成,有非常好的擴充套件性。 |
缺點 | 每次為工廠方法新增新的產品時就要編寫一個新的產品類,同還要引入抽象層,必然會導致程式碼類結構的複雜化。 |
3.工廠方法模式的UML類圖
4.工廠方法模式的實現
對比UML類圖,我們可以寫出工廠方法模式的通用模式程式碼如下:
1.抽象工廠方法(核心),具體生產什麼由子類去實現:
public abstract class Factory {
public abstract Product createProduct ();
}
2.具體工廠類(實現了具體業務邏輯):
public class ConcreteFactory extends Factory{
@Override
public Product createProduct() {
return new ConcreteProductA(); // 返回具體的產品物件
}
}
3.抽象產品類,由具體的產品類去實現:
public abstract class Product {
public abstract void method();
}
4.具體產品類(包含ConcreteProductA、ConcreteProductB等):
public class ConcreteProductA extends Product {
@Override
public void method() {
System.out.println("ConcreteProductA method");
}
}
測試程式:
@Test
public void factoryTest() throws Exception {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct();
product.method();
}
輸出:ConcreteProductA method
這種方式比較常見,需要哪個就生產哪個,有時候還可以利用反射的方式更加簡潔地來生產具體產品物件,此時,需要在工廠方法的引數列表中傳入一個 Class 類來決定是哪一個產品類:
public abstract class Factory {
/**
* @param clz 產品物件類型別
* @param <T> 具體的產品物件
* @return
*/
public abstract <T extends Product> T createProduct(Class<T> clz);
}
對應的具體工廠類則通過反射獲取類的例項即可:
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;
}
}
再看一下測試程式碼的實現:
@Test
public void factoryTest() throws Exception {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct(ConcreteProductA.class);
product.method();
}
輸出:ConcreteProductA method
需要哪個類的物件傳入哪一個類即可,這種方法比較簡潔、動態。如果不喜歡這一種,也可以嘗試為每一個產品都定義一個具體的工廠,各司其職,像擁有多個工廠的方式我們稱為多工廠方法模式,同樣當我們的工廠類只有一個的時候,我們還可以簡化掉抽象類,只需要將對應的工廠方法給為靜態方法即可:
public class Factory {
public static Product createProduct() {
return new ConcreteProductA();
}
}
像這樣的方式又稱為簡單工廠模式或者靜態工程模式,它是工廠模式的一個弱化版本。
5.Android系統原始碼中的應用情景
工廠方法模式應用很廣泛,開發中使用到的資料結構中就隱藏著對工廠方法模式的應用,例如 List、Set,List、Set 繼承自 Collection 介面,而 Collection 介面繼承於 Iterable 介面:
public interface Iterable<T> {
Iterator<T> iterator();
}
這意味著 List、Set 介面也會繼承 iterator() 方法,下面以 ArrayList 為例進行分析:
ArrayList 中 iterator() 方法的實現就是構造並返回一個迭代器物件:
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 物件而生,構造並返回一個具體的迭代器。