標籤:

抽象工廠模式和工廠模式的區別?

看了很多網上的帖子,說區別在於:工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。

工廠方法模式的具體工廠類只能創建一個具體產品類的實例,而抽象工廠模式可以創建多個。

但是看GOF的例子,發現區別貌似不在於此。個人認為抽象工廠模式是把創建者的創建過程和構件分離了,採用了組合的方式。而工廠模式是用繼承的方式將創建過程和構件合在了一起,有沒有對設計模式有研究的,能解答一下


剛擼完,更多詳情可以去我網站上看 DesignPattern

簡單工廠模式

簡單工廠模式不是23種里的一種,簡而言之,就是有一個專門生產某個產品的類。

比如下圖中的滑鼠工廠,專業生產滑鼠,給參數0,生產戴爾滑鼠,給參數1,生產惠普滑鼠。

工廠模式

工廠模式也就是滑鼠工廠是個父類,有生產滑鼠這個介面。

戴爾滑鼠工廠,惠普滑鼠工廠繼承它,可以分別生產戴爾滑鼠,惠普滑鼠。

生產哪種滑鼠不再由參數決定,而是創建滑鼠工廠時,由戴爾滑鼠工廠創建。

後續直接調用滑鼠工廠.生產滑鼠()即可

抽象工廠模式

抽象工廠模式也就是不僅生產滑鼠,同時生產鍵盤。

也就是PC廠商是個父類,有生產滑鼠,生產鍵盤兩個介面。

戴爾工廠,惠普工廠繼承它,可以分別生產戴爾滑鼠+戴爾鍵盤,和惠普滑鼠+惠普鍵盤。

創建工廠時,由戴爾工廠創建。

後續工廠.生產滑鼠()則生產戴爾滑鼠,工廠.生產鍵盤()則生產戴爾鍵盤。

在抽象工廠模式中,假設我們需要增加一個工廠

假設我們增加華碩工廠,則我們需要增加華碩工廠,和戴爾工廠一樣,繼承PC廠商。

之後創建華碩滑鼠,繼承滑鼠類。創建華碩鍵盤,繼承鍵盤類。

即可。

在抽象工廠模式中,假設我們需要增加一個產品

假設我們增加耳麥這個產品,則首先我們需要增加耳麥這個父類,再加上戴爾耳麥,惠普耳麥這兩個子類。

之後在PC廠商這個父類中,增加生產耳麥的介面。最後在戴爾工廠,惠普工廠這兩個類中,分別實現生產戴爾耳麥,惠普耳麥的功能。

以上。


今天正好在學習抽象工廠和工廠方式,我就把我的理解寫一寫。

工廠一般理解就是減少new創建對象的方式,用介面的方式來返回一個對象,而new創建的方式被封裝了。然而,這個是初級認識,這不足以理解到工廠方式的真正目的。

所以我要用我的方式幫助大家理解。

第一部分: 抽象工廠

一般來說,抽象工廠最簡單形態也至少有4個元素:

  • 客戶端(client)
  • 工廠(factory)
  • 產品A(product A)
  • 產品B(product B)

我先用一個例子來實體說明抽象工廠是什麼

我現在有三個神槍手,他們聚在一起討論他們玩槍的經歷,

  • 神槍手1:AK47打槍最好,殺傷力大。
  • 神槍手2:沙漠之鷹最好,准。
  • 神槍手3:連弩才好,上古兵器。

他們爭論相持不下,所以決定比試一下,然後約定一個月後來鄙視。然後我們看到三個人分別去各自的工廠去購買武器。

神射手1 去了AK47工廠,購買他們生產的武器和子彈

神射手2 去了沙漠之鷹工廠,購買他們生產的武器和子彈

神射手3,去了連弩工廠,購買他們生產的武器和「子彈」

一個月後,我們看到了3個人分別拿出來以下的武器組合

這三個人雖然用的武器不一樣,但是每件武器都要做兩件事

最後,他們通過比賽誰,看哪種武器是最優秀的。

我們回頭去看看,發現雖然三個人去了不同的工廠,用了不同的武器,用了不同的子彈,但是他們的相似之處太多,可以抽象出來。抽象出來的關係框架就是抽象工廠模式

  • 武器工廠生產武器
  • 武器工廠生產武器所用的子彈
  • 武器可以裝載子彈
  • 武器可以射擊子彈
  • 神射手裝載子彈
  • 神射手射擊子彈

那麼把關係畫出來就是:

然後抽象一下成工廠模式就是:

圖畫出來了,然後我們要如何理解抽象工廠模式. 過去人們都是從工廠開始解釋,其實我個人覺得,倒過來講反而更好理解。而理解抽象工廠模式的關鍵在於如何理解「產品之間特定關係」。

  1. 用戶要調用產品之間的這個特定關係
  2. 這個特定關係只有產品A和產品B之間才有,所以我們需要產品A和產品B
  3. 要獲得產品A和產品B,我們要去生產這個產品A和產品B的那個工廠,叫工廠生產這個產品A和產品B

那麼用例子來說,就是:

  1. 神槍手喜歡裝載子彈和射擊的感覺(他們就是喜歡這個,只要有武器符合這個條件就行)
  2. 那麼他們就是需要武器(槍或者連弩)和子彈,這個武器是可以裝載相應子彈和射擊相應子彈的
  3. 他們可以去特定工廠(ak47工廠或者連弩工廠)要求購買武器和相應子彈、

所以理順抽象工廠的特點是什麼?就是如下幾個特點:

  • 工廠是獨立的(獨立的類)
  • 工廠是生產一整套有產品的(至少要生產兩個產品),這些產品必須相互是有關係或有依賴的
  • 工廠是可以抽象的,工廠生產是可以抽象的
  • 產品是可以抽象的,產品關係是可以抽象的

  • 客戶端是用來調用並理順這些產品之間的關係(或指定工作流程)
  • 不同工廠生產出的產品實例之間是不接觸的,這個是靠客戶端來封裝實現的。

用一個例子來解釋一下最後一條「不同工廠生產出的產品實例之間是不接觸的,這個是考客戶端來封裝實現的」。

一個射擊學員剛入門,聽到射擊老師說射擊的幾個要素: 武器,子彈,武器裝載子彈,武器打出子彈。這個學員躍躍欲試,就跑到Ak47工廠買了槍,然後跑到沙漠之鷹工廠買了子彈,AK47裝載沙鷹子彈,然後打出。學員卒。

老師聽說後,為了避免這個悲劇發生,承包了武器和子彈購買,要用AK47就必須在AK47工廠購買AK47和AK47子彈,保證了AK47載入沙漠之鷹子彈這樣的悲劇發生了。

這就是客戶端載入工廠實例後,保證只使用這個工廠的生產的產品和產品之間的關係,確保不和其他工廠的產品實例進行接觸。

最終當我們調用客戶端的行為時候,只要讓客戶端「載入」實例化的特定工廠,返回結果就是這個「特定工廠」所加工出來的「特定產品」的「特定關係」方法的結果了。

所以,當產品非常多的時候,產品之間關係又非常複雜,但卻又可以進行抽象的時候,就是使用抽象工廠模式最好的時候了。

以上就是抽象工廠模式的個人理解

--------

第二部分: 工廠方法

工廠方法就兩個元素:

  • creator(創建者)

  • product(產品)

而工廠方法就是一個創建者這個類的一個方法而已,這個方法就是用來封裝產品的創建。

(留坑)

第三部分: 抽象工廠 和工廠方法的不同點

我從一下幾個方面來理解抽象工廠和工廠方法不同點

  • 抽象工程關鍵在於產品之間的抽象關係,所以至少要兩個產品;工廠方法在於生成產品,不關注產品間的關係,所以可以只生成一個產品。

  • 抽象工廠中客戶端把產品的抽象關係理清楚,在最終使用的時候,一般使用客戶端(和其介面),產品之間的關係是被封裝固定的;而工廠方法是在最終使用的時候,使用產品本身(和其介面)。

抽象工廠更像一個複雜版本的策略模式,策略模式通過更換策略來改變處理方式或者結果;而抽象工廠的客戶端,通過更改工廠還改變結果。所以在使用的時候,就使用客戶端和更換工廠,而看不到產品本身。

工廠方法目的是生產產品,所以能看到產品,而且還要使用產品。當然,如果產品在創建者內部使用,那麼工廠方法就是為了完善創建者,從而可以使用創建者。另外創建者本身是不能更換所生產產品的。

  • 抽象工廠的工廠是類;工廠方法的工廠是方法。

抽象工廠的工廠類就做一件事情生產產品。生產的產品給客戶端使用,絕不給自己用。

工廠方法生產產品,可以給系統用,可以給客戶端用,也可以自己這個類使用。自己這個類除了這個工廠方法外,還能有其他功能性的方法

其實仔細想想,這個兩個模式是有交集的,在極端的情況下,這兩個模式其實是一樣的。所以可以這樣理解

  • 給工廠方法模式加一個客戶端,除了客戶端都不用這個創建者。這個時候創建者就是工廠類了。(單一產品的特定關係這個時候就是沒有關係)

  • 抽象工廠模式中,在客戶端內部編程時候,就可以把工廠類當作創建者。


工廠方法模式: 一個抽象產品類,可以派生出多個具體產品類。 一個抽象工廠類,可以派生出多個具體工廠類。 每個具體工廠類只能創建一個具體產品類的實例。 抽象工廠模式: 多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。 一個抽象工廠類,可以派生出多個具體工廠類。 每個具體工廠類可以創建多個具體產品類的實例。 區別: 工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。 工廠方法模式的具體工廠類只能創建一個具體產品類的實例,而抽象工廠模式可以創建多個。


實例 -&> 類 -&> 類工廠

實例 -&> 類 -&> 類工廠 -&> 抽象工廠


工廠方法產生一個橫向維度的子類,子類實現了某個具體功能,例如薯條;要產生雞塊就需要再生成一個雞塊的子類。抽象工廠是直接產生一個縱向維度的類,能否實現的功能已經被打包成一個套餐,例如全家桶,只能享用這個套餐裡面的食物。


你愛吃雞蛋,每次想吃雞蛋都去樓下的雞窩拿一個.這個雞窩就是雞蛋工廠

有一天你突然想吃柴雞蛋,那就得去樓下的雞窩工廠里翻出柴雞蛋工廠,從那拿的就是柴雞蛋.


這裡講一下產品族和產品等級結構:

假設羅技公司有低中高三種工廠,他們同時都生產滑鼠、鍵盤、攝像頭。

那麼這時候低級工廠、中級工廠等就分別是產品族

滑鼠、鍵盤、攝像頭就分別是產品等級結構

圖來自:劉偉技術博客

這裡就省略各種定義了,直接講區別。

在抽象工廠模式中,增加一個產品族很容易,而增加一個產品等級結構卻很難,工廠模式則反之。

也就是說,在抽象工廠模式中,增加一個具體的工廠很容易,但是你想在工廠中多生產一種產品,就需要修改很多個類,會違背開閉原則,這種情況下應該使用工廠模式。


普通工廠產出是一個產品(實例),抽象工廠產出是一個抽象(介面)。區別在於,若添加一個新的產品,前者是修改工廠,後者是創建新工廠(符合「閉合原則」)。


工廠方法模式和抽象工廠模式最大的區別其實就是:

工廠方法模式是生產單個同類型的不同產品,例如戴爾電腦,蘋果電腦

而抽象工廠模式生產的是多個不同類型的不同產品,所以必須將共同點抽象出來,例如戴爾CPU,蘋果CPU,抽象的介面就是CPU。戴爾GPU,蘋果GPU,抽象的介面就是GPU(虛擬例子)。這也是為了遵守面向對象的原則之一,面向介面編程而不是內容編程。


感覺抽象工廠和工廠方法的區別,就是產生內容上一個是面,一個是線,但是在對外上,替換產品族時,抽象工廠就是就是點的概念,這也體現了抽象的概念,內容是大的,但是看上去卻變小了


基本高贊、高評論的答案都不靠譜。反而一些沒人贊、少贊的還靠譜一點。像 @caoglish 這個答案更是把大家帶到溝里去了。什麼抽象工廠模式必須有兩個以上的產品類,純屬瞎扯淡了。

簡單的說,抽象工廠是對簡單工廠(工廠方法模式、工廠模式)中的工廠類進一步抽象成介面,解決了工廠方法中的硬編碼問題,因為以後如有新增新的對象,只要再實現一個對應的工廠類,就完成了擴展。無需修改以前的代碼。

比如 @itishsy 幾句話就說清楚了抽象工廠的核心:

普通工廠產出是一個產品(實例),抽象工廠產出是一個抽象(介面)。區別在於,若添加一個新的產品,前者是修改工廠,後者是創建新工廠(符合「閉合原則」)。


Abstract Factory


工廠模式,返回的產品是抽象。

抽象工廠,獲取的工廠就是抽象,產品也是抽象。

你可以看到,為了實現抽象工廠,你還需要為工廠的產生提供一個工廠的工廠。

工廠返回的不同產品應該有相同的介面。一般來說,讓它們繼承同一個介面類就可以了。

話說java就是喜歡搞這麼多名詞忽悠人,結果最後還讓人搞不清楚。其實別專註於名詞,拿份代碼出來看一遍,就什麼都明白了。工程實現的時候按需使用就行,不用拘泥於XX模式。


Head First Design Pattern 里說的不要太清楚。。。多看看書,樓上很多解釋都什麼鬼啊。

這兩種方法思想是一致的,但是實現方式完全不同。而且針對的場景也不一樣。

下面是我筆記里總結的兩者區別:

One uses inheritance and one uses composition.

One
creates only one product and the other creates a family of products.

One makes
use of the concrete types the subclasses create and the others methods are
purely implemented to create products.


先理解工廠模式,抽象工廠模式相當於在工廠模式外面又加了一層,使得具體創建某個類的方法一樣,通過外面這層來決定具體創建哪一個類。


抽象工廠是在工廠方法的基礎上進一步抽象,所以工廠方法對象對象的方式是子類創建對象,而抽象工廠是子類的子類,是對象組合也是對象家族。


工廠返回實體類實例,抽象工廠返回介面類型。over。


GOF《設計模式》寫的很清楚,工廠方法是由子類自行決定實例化那個類,而抽象工廠是自己決定實例化哪個類。至於是組合還是繼承還是實現介面都無所謂。根本區別在於是自己實例化還是子類實例化。


樓下有三家店:一家水果店,兩家超市

水果店A:賣西瓜 賣香蕉

超市B:賣牛奶 賣飲料

超市C:賣牛奶 賣飲料

A、B、C 都可以用工廠方法描述其行為。

  1. A要賣冰棒,B加要買水果,C加要賣杯子。增加個產品很容易。

有天,B+C 合併 =&> 超市 B2,因為其行為比較相似,就可以用抽象工廠描述其行為。

  1. 擴充產品線:有個超市D, B2+D= 新超市B3。所以擴充產品線很簡單。
  2. 哪天超市B心血來潮,要賣冰棒!那麼C也要賣冰棒,D也要賣冰棒。所以擴充產品很麻煩。

如果A+B 合併 =&>超市A1,就不可以用抽象工廠描述其行為,會出事的。

能用抽象工廠就用抽象工廠,不能用,就別硬用。


抽象工廠的重點在工廠:它產生一系列相關的產品對象,而任何的client只能在這一系列中挑選產品。


同感,好多設計模式都看不出區別,

比如策略模式和狀態模式,

總覺得就是換了個名字,


推薦閱讀:

敏捷開發中如何保證界面設計?
狀態模式和策略模式的區別與聯繫?
一個靜態類或者非靜態類,多個方法依賴一個函數,如何實現?
C++模版類如何動態獲取類型?
c++中如何正確實現克隆(原型)模式?

TAG:設計模式 |