1. 程式人生 > >Java設計模式百例 - 工廠方法模式

Java設計模式百例 - 工廠方法模式

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等等具體實現類。

總結

從上邊的例子可以看到,工廠方法模式其實是將“面向接口”編程的思路應用在了工廠類上,這樣有幾個方便的地方:

  1. 做到了完全的“開閉原則”,因為增加新的“產品”和相應的“工廠”均不需修改現有代碼;

  2. 工廠設計模式通常應用在復雜的對象創建場景中,因此面臨多層的繼承關系,比如ArrayList實現了List接口,而後者繼承自Collect接口,Collect又繼承自Iterator接口。有時候具體工廠方法與具體產品是有層次對應關系的,比如:

技術分享

這種情況也是只有一個工廠類的簡單工廠模式所無法滿足的。


Java設計模式百例 - 工廠方法模式