軟體設計模式系列之三———工廠方法模式

2023-09-12 12:00:31

1 模式的定義

工廠方法模式是一種常見的設計模式,屬於建立型設計模式之一,它在軟體工程中用於物件的建立。該模式的主要思想是將物件的建立過程抽象化,將具體物件的範例化延遲到子類中完成,以便在不同情況下可以建立不同型別的物件,而使用者端程式碼不需要知道實際建立的物件型別。

2 舉例說明

小米和華為都生產自己的手機,就符合工廠方法模式。小米和華為都是手機制造商,而手機則是產品。每家公司都有自己的生產流程和標準,但它們都需要生產手機以滿足市場需求。

工廠方法模式中,每家公司都有一個具體的工廠(小米工廠和華為工廠),這些工廠實現了一個共同的抽象工廠介面。抽象工廠定義了一個方法用於生產手機,但具體的手機生產過程由每家公司的工廠來實現。

使用者端程式碼可以根據需要選擇使用小米工廠或華為工廠來生產手機。這種方式下,使用者端程式碼無需關心手機的具體制造過程,只需知道如何與抽象工廠互動即可。

工廠方法模式的優點在於它實現了物件的建立和使用者端程式碼的解耦,使得不同的工廠可以獨立擴充套件,適用於多樣化的產品生產場景。小米和華為手機的製造就是一個生動的範例,其中工廠方法模式為不同公司的手機生產提供了一種靈活的、可延伸的解決方案

3 結構

工廠方法模式的結構包括以下幾個關鍵角色:

  • 抽象工廠介面(Factory):這是工廠方法模式的核心部分,它定義了一個或多個工廠方法的介面,這些方法用於建立具體產品物件。通常,這個介面中會包含多個方法,每個方法用於建立不同型別的產品。使用者端程式碼通過呼叫這些工廠方法來獲取產品物件。
  • 具體工廠類(Concrete Factory):這是實現抽象工廠介面的具體類,每個具體工廠類負責建立一類具體產品。它實現了工廠方法,根據使用者端的需求建立具體的產品物件。每個具體工廠類通常對應一個特定的產品族。
  • 抽象產品介面(Product):這個介面定義了產品物件的通用屬性和方法,所有具體產品類都必須實現這個介面。使用者端程式碼將與抽象產品介面進行互動,而不直接與具體產品類進行互動。
  • 具體產品類(Concrete Product):這些是實際的產品類,它們實現了抽象產品介面,定義了具體產品的屬性和行為。每個具體產品類對應一個具體工廠類。
  • 使用者端(Client):使用者端程式碼需要建立產品物件,但它不直接與具體產品類或具體工廠類互動。使用者端通過呼叫抽象工廠介面中的工廠方法來建立產品物件,從而實現瞭解耦的目的。

工廠方法模式的結構允許在不修改使用者端程式碼的情況下引入新的具體產品類和具體工廠類,從而增加系統的可延伸性。使用者端只需要知道抽象工廠介面和抽象產品介面,而不需要關心具體的產品類和工廠類,這使得系統更易於維護和擴充套件。

總結來說,工廠方法模式的結構包括抽象工廠介面、具體工廠類、抽象產品介面、具體產品類以及使用者端。這個模式通過將物件的建立委託給具體工廠類來實現物件的建立和使用者端與產品之間的解耦。

4 實現步驟

工廠方法模式的實現步驟通常包括以下幾個關鍵步驟:

  • 定義抽象產品介面(Product):定義一個抽象產品介面,它宣告了產品物件的通用屬性和方法。所有具體產品類都必須實現這個介面。
  • 建立具體產品類(Concrete Product):實現抽象產品介面的具體產品類。每個具體產品類表示一種具體的產品。
  • 定義抽象工廠介面(Factory):建立一個抽象工廠介面,該介面宣告了工廠方法,用於建立產品物件。
  • 建立具體工廠類(Concrete Factory):實現抽象工廠介面的具體工廠類,每個具體工廠類負責建立特定型別的產品。在使用者端中使用工廠方法:
  • 使用者端程式碼通過具體工廠類的工廠方法來建立產品物件,而不直接範例化具體產品類。

通過上述步驟,您就可以實現工廠方法模式。這種模式允許使用者端根據需要選擇合適的具體工廠來建立產品,從而實現瞭解耦和可延伸性。如果需要新增新的產品型別,只需建立新的具體產品類和對應的具體工廠類,而不需要修改現有的使用者端程式碼。

5 程式碼實現

以下是使用工廠方法模式實現抽象工廠(AbstractFactory)、具體工廠(XiaomiFactoryHuaweiFactory)、抽象產品(AbstractMobile)和具體產品(XiaomiMobileHuaweiMobile)的Java程式碼範例:

// 抽象產品介面
interface AbstractMobile {
    void displayInfo();
}

// 具體產品類 - 小米手機
class XiaomiMobile implements AbstractMobile {
    @Override
    public void displayInfo() {
        System.out.println("這是小米手機。");
    }
}

// 具體產品類 - 華為手機
class HuaweiMobile implements AbstractMobile {
    @Override
    public void displayInfo() {
        System.out.println("這是華為手機。");
    }
}

// 抽象工廠介面
interface AbstractFactory {
    AbstractMobile createMobile();
}

// 具體工廠類 - 小米工廠
class XiaomiFactory implements AbstractFactory {
    @Override
    public AbstractMobile createMobile() {
        return new XiaomiMobile();
    }
}

// 具體工廠類 - 華為工廠
class HuaweiFactory implements AbstractFactory {
    @Override
    public AbstractMobile createMobile() {
        return new HuaweiMobile();
    }
}

// 使用者端
public class Client {
    public static void main(String[] args) {
        // 使用具體工廠建立具體產品
        AbstractFactory xiaomiFactory = new XiaomiFactory();
        AbstractMobile xiaomiMobile = xiaomiFactory.createMobile();
        xiaomiMobile.displayInfo();

    AbstractFactory huaweiFactory = new HuaweiFactory();
        AbstractMobile huaweiMobile = huaweiFactory.createMobile();
        huaweiMobile.displayInfo();
    }
}


在這個程式碼範例中,我們定義了抽象產品介面 AbstractMobile 和兩個具體產品類 XiaomiMobileHuaweiMobile。然後,我們定義了抽象工廠介面 AbstractFactory,其中包含了一個工廠方法 createMobile(),用於建立手機產品。

接下來,我們建立了兩個具體工廠類 XiaomiFactoryHuaweiFactory,分別實現了 AbstractFactory 介面,並在其中實現了工廠方法,分別用於建立小米手機和華為手機。

最後,在使用者端程式碼中,我們使用不同的具體工廠來建立不同的手機產品,從而實現了工廠方法模式,使用者端程式碼不需要知道具體產品的細節,只需要知道如何使用抽象工廠來建立產品

6 典型應用場景

6.1 資料庫驅動程式的建立

使用工廠方法模式來進行資料庫驅動程式建立的場景是在軟體開發中需要連線不同型別的資料庫(例如MySQL、PostgreSQL、Oracle等)時。通過工廠方法模式,可以將不同資料庫的連線物件的建立過程封裝在各自的工廠類中,使用者端程式碼無需關心具體的資料庫驅動程式實現,只需使用相應的工廠來建立資料庫連線物件,從而實現了靈活性和可延伸性,能夠輕鬆地切換和新增新的資料庫驅動程式,而不影響現有的程式碼。這種模式在多資料庫支援和資料庫連線的抽象化方面非常有用。

6.1 UI控制元件的建立

使用工廠方法模式進行UI控制元件建立的場景是在圖形化使用者介面(GUI)開發中。不同作業系統或介面庫(如Windows、macOS、Android等)可能使用不同的UI控制元件(如按鈕)。通過工廠方法模式,可以將每種UI控制元件的建立過程封裝在各自的工廠類中,使用者端程式碼無需關心具體的控制元件實現,只需使用相應的工廠來建立控制元件物件,從而實現了跨平臺和可延伸性,使得應用程式能夠在不同的作業系統或介面庫下建立合適的UI控制元件,而不需要重寫整個介面程式碼。這種模式在多平臺UI開發和UI元件的抽象化方面非常有用。

6.3 紀錄檔記錄器

在應用程式中需要記錄紀錄檔以進行偵錯、故障排除和效能監測時。不同的紀錄檔記錄方式(如檔案紀錄檔、資料庫紀錄檔、控制檯紀錄檔等)可能需要使用不同的紀錄檔記錄器。通過工廠方法模式,可以將每種紀錄檔記錄器的建立過程封裝在各自的工廠類中,使用者端程式碼無需關心具體的紀錄檔記錄器實現,只需使用相應的工廠來建立紀錄檔記錄器物件,從而實現了靈活性和可延伸性,使得應用程式可以根據需求選擇不同的紀錄檔記錄方式,而不需要修改主要的應用邏輯。這種模式在紀錄檔記錄方式的切換和客製化化紀錄檔記錄方面非常有用。

6.4 遊戲中不同角色的建立

使用工廠方法模式來建立遊戲中不同角色的場景是在遊戲開發中。在遊戲中,有各種不同型別的角色(如玩家、敵人、道具、NPC等),每個角色都有自己獨特的屬性和行為。通過工廠方法模式,可以將每種角色的建立過程封裝在各自的工廠類中,使用者端程式碼無需關心具體的角色實現,只需使用相應的工廠來建立角色物件,從而實現了遊戲角色的動態建立和管理。這種模式在遊戲中角色的擴充套件和多樣化方面非常有用,使得遊戲開發人員可以輕鬆地新增新的角色型別,而不需要修改遊戲引擎或核心邏輯。

7 優缺點

工廠方法模式是一種常用的設計模式,它具有一些優點和缺點:

優點:

鬆耦合 :工廠方法模式將物件的建立過程封裝在工廠類中,使用者端程式碼與具體產品類解耦。使用者端程式碼只需要關心抽象工廠和產品介面,無需瞭解具體產品的細節。

可延伸性 :通過新增新的具體工廠類和具體產品類,可以輕鬆擴充套件系統以支援新的產品型別,而不需要修改現有的程式碼。這使得系統更容易維護和擴充套件。

多型性 :工廠方法模式利用了多型性,使得使用者端可以根據需要建立不同型別的產品物件,而無需改變使用者端程式碼。

符合開閉原則 :工廠方法模式遵循開閉原則,對修改關閉,對擴充套件開放。新增新的產品型別只需要新增新的具體工廠類和具體產品類,而不需要修改現有程式碼。

缺點:

類的數量增加 :引入工廠方法模式會增加類的數量,每個具體產品類都需要一個對應的具體工廠類。對於一些簡單的情況,可能會使程式碼變得複雜。

複雜性增加 :在有多層繼承結構的情況下,可能會引入更多的層次,增加程式碼的複雜性。

不適用於單例 :工廠方法模式通常用於建立多個物件,不適用於建立單例物件。對於單例模式,通常使用其他模式,如單例模式或者靜態工廠方法。

增加程式碼複雜度 :在簡單情況下,使用工廠方法模式可能會增加不必要的複雜性,不如直接範例化物件來得簡單。

總之,工廠方法模式在實現物件的建立和使用者端程式碼解耦方面有很多優點,但也需要謹慎使用,根據具體情況來決定是否使用該模式,以確保程式碼的可維護性和擴充套件性。

8 類似模式

工廠方法模式、抽象工廠模式和簡單工廠模式都是建立型設計模式,用於物件的建立,但它們在關注點和應用場景上存在差異。

簡單工廠模式是一種簡化物件建立的方法,不是 GoF(Gang of Four)的正式設計模式。簡單工廠適用於建立少量的物件,但不符合開閉原則,不支援擴充套件新的產品型別。

工廠方法模式是一種正式的設計模式,定義了一個建立物件的介面,具體的物件建立延遲到子類中完成。用於建立單一產品等級結構。

抽象工廠模式也是一種正式的設計模式,提供一個介面,用於建立一系列相關或依賴的物件,不需要指定具體的類。每個具體工廠類可以建立一組相關的產品,用於建立多個相關的產品等級結構或整個產品族。

它們都以不同的方式提供了物件建立的靈活性和可延伸性,根據需求選擇合適的模式。

9 小結

工廠方法模式是一種常用的設計模式,屬於建立型設計模式,其核心思想是將物件的建立延遲到子類中去完成。特別適合在需要建立多個相關但不同型別的物件時,以提高程式碼的可維護性和可延伸性。它將物件的建立過程進行了抽象,使得使用者端程式碼更加靈活,可以根據需要選擇不同的具體工廠來建立物件。