Java設計模式百例 - 工廠方法模式
本文源碼見:https://github.com/get-set/get-designpatterns/tree/master/factory-method
工廠方法模式同簡單工廠模式一樣,也是創建類模式,又叫做虛擬構造(Virtual Constructor)模式或多態工廠(Polymorphic Factory)模式。其用意是定義一個創建產品對象的工廠接口,將實際創建工作推遲到子類中。
上篇說到,簡單工廠模式並未做到完全的“開閉原則”。回顧一下,“開”即對擴展開放,這點是沒錯的,簡單工廠模式的初衷之一就是方便增加“產品類型”的時候;“閉”即對修改關閉,這點其實並未做到,當需要增刪改“產品類型”的時候,工廠類必須要修改,因為工廠類“知道”如何創建所有的產品類型的對象。
那麽工廠方法模式就是為了完全滿足“開閉原則”,即在簡單工廠模式的基礎上,做到當增加產品類型的時候,無需改動現有的代碼。繼續用上篇的例子:
例子
仍然是做一個畫圖軟件,可以畫矩形、三角形和圓形等,每一種圖形都用一個類來管理:
* Rectangle
* Circle
* Triangle
每個類都有各自的draw()
方法,共同實現Shape
接口。
Shape.java
public interface Shape { void draw(); }
Rectangle.java
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Draw a rectangle."); } }
Triangle.java
public class Triangle implements Shape { @Override public void draw() { System.out.println("Draw a triangle."); } }
Circle.java
public class Circle implements Shape { @Override public void draw() { System.out.println("Draw a circle."); } }
以上幾個類都沒有變化,有變化的是工廠類,工廠類也采用基於接口的設計,由不同的具體工廠類負責相應對象的創建:
ShapeFactory.java
public interface ShapeFactory { Shape getShape(); }
RectangleFactory.java
public class RectangleFactory implements ShapeFactory { public Shape getShape() { return new Rectangle(); } }
CircleFactory.java
public class CircleFactory implements ShapeFactory{ public Shape getShape() { return new Circle(); } }
Triangle.Factory.java
public class CircleFactory implements ShapeFactory{ public Shape getShape() { return new Circle(); } }
那麽在需要某個形狀的時候,就通過相應的具體工廠類創建即可:
Client.java
public class Client { public static void main(String[] args) { ShapeFactory factory = new CircleFactory(); Shape c = factory.getShape(); c.draw(); } }
再來看一下類圖:
與簡單工廠模式對比以下:
區別就在於簡單工廠模式下的一個具體的工廠類轉換成了基於接口ShapeFactory
的三個具體工廠類。
好處也是明顯的:當增加一個新的形狀類型的時候,不需要對現有代碼做任何更改,增加一個相應的實現了ShapeFactory
的具體工廠類即可。可見,工廠方法模式能夠完全做到“開閉原則”。
這個例子仍然是不恰當的,因為無論如何這一套模式設計比原始的實現方式有更加復雜了。所以再次贅述一遍註意事項,以上例子是為了說明工廠方法模式,但並不是一個合理的應用。復雜對象適合使用工廠模式,而簡單對象,特別是只需要通過 new 就可以完成創建的對象,無需使用工廠模式。如果使用工廠模式,就需要引入一個工廠類,會增加系統的復雜度。
Java中的應用
下邊看一下合理的應用場景是如何的,在Java中的實際應用的例子(來自《Java與模式》):
* 1. Java聚集中的應用 *
Java聚集是一套設計精良的數據結構實現,主要的Java聚集都實現自java.util.Collection
接口,這個接口的父接口Iterable
規定所有的Java聚集都必須提供一個iterator()
方法,返還一個Iterator
類型的對象:
java.lang.Iterable.java
public interface Iterable<E> { ... ... Iterator<E> iterator(); ... ... }
ArrayLis是我們常用的一個Collection實現類,其iterator()方法實現如下:
java.util.ArrayList.java
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ... ... // 實現iterato接口,返回一個Iterator對象 public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { ... ... } ... ... }
可見,ArrayList
類的iterator()
方法就是一個具體工廠類的工廠方法,而Collection
就是一個抽象工廠。除了ArrayList
還有LinkedList
等等具體實現類。
總結
從上邊的例子可以看到,工廠方法模式其實是將“面向接口”編程的思路應用在了工廠類上,這樣有幾個方便的地方:
做到了完全的“開閉原則”,因為增加新的“產品”和相應的“工廠”均不需修改現有代碼;
工廠設計模式通常應用在復雜的對象創建場景中,因此面臨多層的繼承關系,比如
ArrayList
實現了List
接口,而後者繼承自Collect
接口,Collect
又繼承自Iterator
接口。有時候具體工廠方法與具體產品是有層次對應關系的,比如:
這種情況也是只有一個工廠類的簡單工廠模式所無法滿足的。
Java設計模式百例 - 工廠方法模式