簡單工廠模式

簡單工廠模式 #


  • ChatGPT 的說明

簡單工廠模式(Simple Factory Pattern)是一種創建型設計模式,屬於工廠模式的變體。它旨在提供一個通用的、用於創建物件的接口,而隱藏創建物件的具體細節。簡單工廠模式由三個主要部分組成:[客戶類別](Client class):客戶是使用工廠模式的程式碼部分。客戶透過呼叫簡單工廠裡的公開方法(例:getProduct()),請求工廠創建具體產品的物件。[工廠類別](Factory Class):工廠類別負責生成具體的物件。這個類別通常包含一個(或多個)靜態方法,根據輸入的參數或條件建立不同類型的物件。[具體產品類別](Concrete Product Class):具體產品類別是簡單工廠最後會產出的物件,工廠類別透過判斷條件或參數來建立不同的特定產品物件。(可選)[抽象產品類別](Abstract Product Class):在某些簡單工廠中還會定義一個抽象產品類別。該類別定義了產品物件的通用接口,它是所有特定產品類別的共同父類別或介面。

簡單工廠模式的步驟如下:首先,定義一個抽象的產品類,讓該類別定義一些產品的共同介面或抽象方法,或者直接建立具體的產品類,實作抽象產品類別的介面或方法,定義具體產品的屬性與行為。接著,建立一個工廠類別,該工廠類別可以包含一個靜態方法或非靜態方法,根據輸入參數或條件建立並傳回特定產品的實例。最後,客戶端可以透過呼叫工廠類別的靜態(或非靜態)方法來取得所需的具體產品實例。

簡單工廠模式包含著幾個優點:它可以封裝物件的建立過程。透過簡單工廠模式,客戶端可以在「不需要知道物件的具體建立細節」的前提下獲得物件。降低了客戶端與特定產品類別之間的耦合度。除此之外,這種做法也提升了程式的靈活性,因為客戶端只需要依賴於工廠所提供的方法或介面即可,不需要依賴任何的具體產品。再來,工廠可以根據不同的需要,動態切換回傳給客戶的具體產品類,而不影響需要客戶端的程式碼 …。然而,簡單工廠模式還是有著一些缺點的:例如每次增加新的產品類型時,都需要修改工廠類,違反了開放封閉原則。除此之外,在一些複雜的場景下,可能會導致簡單工廠需要負責過多的產品細節,使得類別變得過與旁大過於臃腫,進而違反單一職責原則

  • 簡單整理

問題描述:Client 對於 Product 有著高度的依賴

解決方案:透過建立一個 Factory 類別,解決客戶與產品間的依賴

程式細節:參照下面的段落

UML 圖:

image

  • 程式碼範例

在常見的設計模式當中,與「工廠」有關的設計模式共有三種,它們由間單到複雜依序是簡單工廠模式、工廠方法模式、以及抽象工廠模式。簡單工廠模式顧名思義,就是透過一個「工廠」類別,將比較「簡單的」程次區域給獨立出來,通常會配合單一職責原則進行程式碼的檢查,如果某一段程式不符合單一職責原則的話,就可以考慮用簡單工廠將程式給區分出來。讓我們用一個簡單的範例來做說明:假設我們正在開發一個「線上傢俱閱覽系統」,使用者可以根據不同的需要來瀏覽、比較、或購買傢俱,程式片段大致如下所述:

// 系統中的 [顧客] 類別
class Customer {
    private String account;
    private String password;

    // 透過不同的關鍵字,取得不同傢俱
    public Furniture getFurniture(String name) {
        Furniture furniture = null;

        if(name.equal("chair"))
            furniture = new Chair();
        else if(name.equals("desk"))
            furniture = new Desk();
        else if(name.equals("sofa"))
            furniture = new Sofa();
        else if(name.equals("bed"))
            furniture = new Bed();
        else if(name.equals("television"))
            furniture = new Television();
        else
            throw new FurnitureIsNotExistException();

        return furniture;
    }
}

上圖的程式邏輯本身沒什麼問題,透過 getFurniture() 方法,我們的確可以讓顧客在系統中正確地看到他們想要留懶的不同傢俱。但從設計原則上,這樣的寫法就有可以改進的空間了,因為這支程式並不符合單一職責原則。白話文的來說: Customer 類別所負責的職責,應該僅限於跟「顧客」有關的東西才對,像是修改密碼、檢視帳戶資料、升級成 VIP 會員、儲值、訂閱相關資訊或取消訂閱 …等。但這個 getFurniture() 方法很明顯是在「創建一個傢俱,並回傳給使用者。」比起顧客,更像是「傢俱」類別的工作,因此針對這個部分,我們可以利用簡單工廠模式對程式進行改寫:

// 系統中的 [顧客] 類別
class Customer {
    // 新增一個 [傢俱工廠]
    private FurnutireFactory factory;
    private String account;
    private String password;

    public Furniture getFurniture(String name) {
        // 將「獲得傢俱」的程式封裝起來
        Furniture furniture = factory.createFurniture(name);
        return furniture;
    }
}
// 系統中的 [傢俱工廠] 類別
class FurnutireFactory {
    public Furniture createFurniture(String name) {
        Furniture furniture = null;

        // 把「獲得傢俱」的程式邏輯擺放在 [傢俱工廠] 裡面
        if(name.equal("chair"))
            furniture = new Chair();
        else if(name.equals("desk"))
            furniture = new Desk();
        else if(name.equals("sofa"))
            furniture = new Sofa();
        else if(name.equals("bed"))
            furniture = new Bed();
        else if(name.equals("television"))
            furniture = new Television();
        else
            throw new FurnitureIsNotExistException();

        return furniture;
    }
}
// 系統中的 [傢俱] 類別(抽象的)
abstract class Furnutire {
    protected String name;

    public Furnutire(String name) {
        this.name = name;
    }
}
// 其他繼承了 [傢俱] 的不同真實傢俱

class Chair {
    public Chair(String name) {
        super(name);
    }
}

class Table {
    public Table(String name) {
        super(name);
    }
}

class Lamp {
    public Lamp(String name) {
        super(name);
    }
}

class Computer {
    public Computer(String name) {
        super(name);
    }
}

這就是簡單工廠的具體範例了。

執得一提的是,因為簡單工廠真的很簡單,因此在一些程式設計上,我們更傾向於把簡單工廠的方法(或方法們)宣告成靜態的(也就是加上 static 關鍵字)。因為如果將方法宣告成靜態方法,其他類別(例如 Customer)在調用工廠中的方法時,就不需要再額外 new 一個工廠的物件出來,算是一種節省記憶體空間的操作。而這種把方法宣告成靜態的撰寫方式也可以稱為「靜態工廠」。但需要注意的是:靜態工廠並不是一種模式,僅僅是一種工廠模式的優化方法而已:

class FurnutireFactory {
    // 加入 static 關鍵字,使其成為靜態方法
    public static Furniture createFurniture(String name) {
        Furniture furniture = null;

        if(name.equal("chair"))
            furniture = new Chair();
        else if(name.equals("desk"))
            furniture = new Desk();
        else if(name.equals("sofa"))
            furniture = new Sofa();
        else if(name.equals("bed"))
            furniture = new Bed();
        else if(name.equals("television"))
            furniture = new Television();
        else
            throw new FurnitureIsNotExistException();

        return furniture;
    }
}
// 系統中的 [顧客] 類別
class Customer {
    private String account;
    private String password;

    public Furniture getFurniture(String name) {
        // 透過 [傢俱工廠] 直接獲得傢俱
        // 省去了建立物件的過程
        Furniture furniture = FurnutireFactory.createFurniture(name);
        return furniture;
    }
}