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();
    }
}

再來看一下類圖:

與簡單工廠模式對比以下:

factorymethod.png

區別就在于簡單工廠模式下的一個具體的工廠類轉換成了基于接口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接口。有時候具體工廠方法與具體產品是有層次對應關系的,比如:
hiera-factory-method.png

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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 原文鏈接:http://blog.csdn.net/zhangerqing http://www.cnblogs....
    孤獨雜貨鋪閱讀 1,534評論 0 3
  • 一、設計模式的分類 總體來說設計模式分為三大類: 創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者...
    RamboLI閱讀 773評論 0 1
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,778評論 18 399
  • 在深夜 安靜的小巷 隱約地傳來淅淅瀝瀝 是天的哭泣 還是水的遷徙 不,什么也不是 什么也不會是 就像孩子的夢境 就...
    柏舟澤閱讀 123評論 0 1
  • 那個晚上雨大得厲害。我先是在看李零譯注的《孫子兵法》,里面高智慧濃縮的戰術語錄和譯文后面綿長而無味的校記弄得我的腦...
    趙天一閱讀 578評論 0 5