Design Patterns 之工廠模式

碩子鴿發表於2020-11-24

現實生活中,原始社會自給自足(沒有工廠),農耕社會小作坊(簡單工廠,民間酒坊),工業革命流水線(工廠方法,自產自銷),現代產業鏈代工廠(抽象工廠,富士康)。

我們的專案程式碼同樣是由簡到繁一步一步迭代而來的,但對於呼叫者來說,卻越來越簡單。

定義

工廠模式的定義:定義一個建立產品物件的工廠介面,將產品物件的實際建立工作推遲到具體子工廠類當中。

按實際業務場景劃分,工廠模式有 3 種不同的實現方式,分別是簡單工廠模式、工廠方法模式和抽象工廠模式。

下面我們來分別看一下這 3 種模式。

一、簡單工廠模式

在簡單工廠模式中建立例項的方法通常為靜態(static)方法,因此 簡單工廠模式 又叫作 靜態工廠方法模式

簡單來說,簡單工廠模式有一個具體的工廠類,可以生成多個不同的產品,屬於建立型設計模式。簡單工廠模式不在 GoF 23 種設計模式之列。

簡單工廠模式每增加一個產品就要增加一個具體產品類和一個對應的具體工廠類,這增加了系統的複雜度,違背了“開閉原則”。

下面來看一個例子:

化妝品工廠可以生產出面霜和爽膚水。


呼叫方直接使用 化妝品工廠 的靜態方法即可生產出化妝品。

class 化妝品工廠 {
    public 化妝品 生產化妝品() {
    	化妝品 res = new 化妝品;
    	if (條件...) {
			System.out.println("化妝品工廠生成-->面霜...");
        	res = new 面霜();	
		} else () {
			System.out.println("化妝品工廠生成-->爽膚水...");
			res = new 爽膚水();
		}
		return res;
    }
}

如果我們新增一個化妝品叫做 潔面乳 ,那麼我們不僅要新建一個類叫做 潔面乳 ,還要改動化妝品工廠中的程式碼。

這就是他的缺點,不符合開閉原則,所以 23 種設計模式中都沒有它。

下面介紹他的改進版。


二、工廠方法模式

“工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來程式碼的情況下引進新的產品,即滿足開閉原則。

如果要新增加一個化妝品的種類潔面乳,按照簡單工廠的做法就需要新建一個類,還要 修改化妝品工廠中的程式碼 ,如果使用工廠方法模式,就不用修改抽象工廠中的程式碼了,只需要再額外增加一個具體工廠就可以了。


在抽象工廠中定義方法,然後在具體工廠中可以實現建立具體物件的邏輯。

//具體工廠-面霜工廠:實現了面霜的生成方法
class 面霜工廠 implements 化妝品工廠 {
    public 化妝品 生產化妝品() {
        System.out.println("面霜工廠生成-->面霜...");
        return new 面霜();
    }
}
//具體工廠-爽膚水工廠:實現了爽膚水的生成方法
class 爽膚水工廠 implements 化妝品工廠 {
    public 化妝品 生產化妝品() {
        System.out.println("爽膚水工廠生成-->爽膚水...");
        return new 爽膚水();
    }
}

以上就是抽象方法模式。


三、抽象工廠模式

在上面的例子的基礎上,如果我們還要引入化妝品的品牌,那麼就會更加複雜一點,工廠方法模式已經滿足不了需求了,需要使用抽象工廠模式。

之前我們討論的都是某一個工廠只生產某一種商品,比如面霜工廠只生產面霜,但是在實際生活中,往往是同一個品牌的產品在一個工廠中生產,比如歐萊雅這個品牌的化妝品應該都是在歐萊雅工廠中生產的,納愛斯的化妝品都是在納愛斯工廠生產的。

抽象工廠的好處在於:對於呼叫者來說,不需要具體的指定某一個實現類,比如我們想要一個歐萊雅面霜,那麼我們可以直接跟歐萊雅工廠說我要面霜,他生產的肯定是歐萊雅的面霜,不可能是納愛斯的面霜。

他和工廠方法模式的區別在於,工廠方法模式的具體工廠中只能建立一個產品類,而抽象工廠模式中有很多方法,可以建立多個產品類,而且可以保證這些類都屬於同一個品牌,即是同一類的。


下面僅展示具體工廠的實現程式碼:

class 歐萊雅工廠 implements 抽象工廠 {
    public 潔面乳 生產潔面乳() {
        System.out.println("歐萊雅工廠 生成-->歐萊雅潔面乳...");
        return new 歐萊雅潔面乳();
    }
    public 爽膚水 生產爽膚水() {
        System.out.println("歐萊雅工廠 生成-->歐萊雅爽膚水...");
        return new 歐萊雅爽膚水();
    }
    public 潔面乳 生產潔面乳() {
        System.out.println("歐萊雅工廠 生成-->歐萊雅潔面乳...");
        return new 歐萊雅潔面乳();
    }
}

最後我們再來探討一下抽象工廠模式的 開閉原則

抽象工廠模式的擴充套件有一定的 開閉原則 傾斜性

  • 當增加一個新的產品族時只需增加一個新的具體工廠,不需要修改原始碼,滿足開閉原則。
  • 當產品族中需要增加一個新種類的產品時,則所有的工廠類都需要進行修改,不滿足開閉原則。

當系統中只存在一個等級結構的產品時,抽象工廠模式將退化到工廠方法模式。

相關文章