【Java設計模式】系列二:工廠方法模式

大千世界,茫茫人海,相識就是一種緣分。若此篇文章對您有幫助,點個贊或點個關注唄!

前言

繼上一篇文章:【Java設計模式】系列一:簡單工廠模式

在簡單工廠模式中,只提供了一個工廠類,該工廠類對產品類進行實例化,按照設定的處理邏輯,需求化的實例化哪一個產品類。簡單工廠模式最大的缺點是當有新產品加入到系統中時,必須修改工廠類,加入必要的處理邏輯,這就違背了七大原則中的“開閉原則”。在簡單工廠模式中,所有的產品都是由同一個工廠創建,工廠職責較重,業務邏輯較爲複雜,具體產品與工廠類之間的耦合度較高,嚴重影響了系統的靈活性和可擴展性,而工廠方法基於上述缺點得以優化。

工廠方法模式

工廠方法模式(Factory Method Pattern) 又稱爲工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式。定義一個創建對象的抽象方法,由子類決定要實例化的類。工廠方法模式將對象的實例化推遲到子類。

工廠模式包含如下具體角色:

  • Product: 抽象產品,定義產品的規範,描述產品的具體特性和功能。
  • ConcreteProduce: 具體產品,實現抽象產品角色所定義的接口,由具體工廠來創建。
  • Factory: 抽象工廠,提供創建產品的接口,調用者通過訪問具體工廠方法的來創建產品。
  • ConcreteFactory: 具體工廠,主要實現抽象工廠中的抽象方法,完成具體產品的實例化。

代碼示例: 生產汽車案例
創建汽車生產的抽象類(Product:抽象產品角色)

package com.designMode;

/**
 * @Author:bnli
 * @Date:2020/2/8 10:19
 */
public abstract class Care {
    public abstract void produceCar();
}

創建生產路虎攬勝的類(ConcreteProduct:具體產品角色)

package com.designMode;

/**
 * @Author:bnli
 * @Date:2020/2/8 10:25
 */
public class LuhuCar extends Car {
    @Override
    public void produceCar() {
        System.out.println("生產路虎攬勝汽車!");
    }
}

創建生產大衆途銳的類(ConcreteProduct:具體產品角色)

package com.designMode;

/**
 * @Author:bnli
 * @Date:2020/2/5 10:27
 */
public class DazCar extends Car {
    @Override
    public void produceCar() {
        System.out.println("生產大衆途銳汽車!");
    }
}

創建抽象工廠類(Factory:抽象工廠)

package com.designMode;

/**
 * @Author:bnli
 * @Date:2020/2/8 10:30
 */
public abstract class AcarFactory {
    public abstract Car getCarFactory();
}

創建路虎攬勝工廠類(ConcreteFactory:具體工廠)

package com.designMode;

/**
 * @Author:bnli
 * @Date:2020/2/8 10:35
 */
public class LuhuaFactory extends AcarFactory {
    public Car getCarFactory() {
        return new LuhuCar();
    }
}

創建大衆途銳工廠類(ConcreteFactory:具體工廠)

package com.designMode;

/**
 * @Author:bnli
 * @Date:2020/2/8 10:37
 */
public class DazFactory extends AcarFactory {
    public Car getCarFactory() {
        return new DazCar();
    }
}

創建測試類:

package com.designMode;

/**
 * @Author:bnli
 * @Date:2020/2/8 10:50
 */
public class TestCarT {
    public static void main(String[] args) {
        LuhuaFactory luhuaFactory = new LuhuaFactory();
        Car carl = luhuaFactory.getCarFactory();
        carl.produceCar();

        DazFactory dazFactory = new DazFactory();
        Car card = dazFactory.getCarFactory();
        card.produceCar();
    }
}

測試結果:
在這裏插入圖片描述
轉成UML圖:
在這裏插入圖片描述
在這裏插入圖片描述
工廠方法模式分析總結:

如需拓展其他產品類,只需在最外層添加,不會修改核心代碼,符合“符合開閉原則”,解決簡單工廠模式的缺點。

工廠方法模式就是對簡單工廠模式的改進(或者進一步的抽象),將工廠抽象成兩層,AbstractFactory(抽象工廠)和具體實現的工廠子類,程序可以根據創建對象的類型使用對應的工廠子類創建對象。這樣講單個的簡單工廠類變成工廠簇,更有利於代碼的維護和擴展。

優點與缺點對比:

優點:

  • 基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它能夠使工廠可以自主確定創建何種產品對象,而如何創建這個對象得細節則完全封裝在具體工廠內部。工廠方法模式之所以稱之爲多態工廠模式,是因爲所有的具體工廠類都具有同一抽象父類。
  • 使用工廠方法模式的另一個優點是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就可以了。這樣,系統的可擴展性也就變得非常好,完全符合“開閉原則”。

缺點:

  • 拓展新產品時,需要重新編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在一定程度上增加了系統的複雜度,有更多的類需要編譯和運行,會給系統帶來一些額外的開銷。
  • 由於考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度。

應用場景:
比如 java.util.Collection 接口的iterator()、Java 消息服務JMS(Java Messaging Service) 、JDBC 中的工廠方法等。

工廠方法模式的適用環境:

  • 一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。
  • 一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
  • 將創建對象的任務委託給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。

工廠方法模式擴展:

  • 使用多個工廠方法 : 在抽象工廠角色中可以定義多個工廠方法,從而使具體工廠角色實現這些不同的工廠方法,這些方法可以包含不同的業務邏輯,以滿足對不同的產品對象的需求。
  • 產品對象的重複使用 : 工廠對象將已經創建過的產品保存到一個集合(如數組、List 等)中,然後根據客戶對產品的請求,對集合進行查詢。如果有滿足要求的產品對象,就直接將該產品返回客戶端;如果集合中沒有這樣的產品對象,那麼就創建一個新的滿足要求的產品對象,然後將這個對象在增加到集合中,再返回給客戶端。
  • 多態性的喪失和模式的退化 : 如果工廠僅僅返回一個具體產品對象,便違背了工廠方法的用意,發生退化,此時就不再是工廠方法模式了。一般來說,工廠對象應當有一個抽象的父類型,如果工廠等級結構中只有一個具體工廠類的話,抽象工廠就可以省略,也將發生了退化。當只有一個具體工廠,在具體工廠中可以創建所有的產品對象,並且工廠方法設計爲靜態方法時,工廠方法模式就退化成簡單工廠模式。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章