抽象工廠模式 建立型 設計模式(四)

 
抽象工廠模式是工廠方法模式的進一步抽象
 
在工廠模式中,客戶端程序依賴(消費)一種抽象產品角色Product
全部的ConcreteCreator的返回類型都是Product,由於抽象工廠角色Creator就是返回Product 
可是,若是一個系統須要依賴多個不一樣的抽象產品角色怎麼辦?
也就是須要Product1 Product2 ... 他們是不一樣的抽象角色,工廠模式就歇菜了,簡單工廠模式也只是一種類型
此時,就須要抽象工廠模式,抽象工廠模式能夠建立多種類型的產品
簡言之,工廠模式只能生產一種產品,好比青島啤酒廠生產各式樣的啤酒,他不可能生產大米
抽象工廠角色就能夠生產啤酒和大米
 

產品族與產品等級

想要理解抽象工廠的本質,須要先介紹兩個概念
產品族和產品等級結構
產品等級結構指的是產品的分類劃分結構
功能相關聯的不一樣產品(位於不一樣的等級結構)就組成了一個產品族
 
咱們舉例說明
好比實際項目中,DAO(數據庫訪問層)都有CRUD 操做(增查改刪)
可是有不一樣的數據庫,假設使用MYSQL和ORACLE兩種數據庫
那麼對於CRUD操做都有兩種類型 MYSQL和ORACLE
產品的等級結構以下圖所示
image_5bea7dea_4170
CRUD操做四個操做對應四個等級產品(簡單理解就是四種類型產品)
四個等級中的MYSQL 就組成了一個產品族
四個等級中的ORACLE 也組成了一個產品族
 
再好比 快餐店常常都有銷售雞腿和漢堡(兩種產品)
可是有不一樣的快餐店,好比KFC和Mcdonalds
產品的等級結構以下圖
image_5bea7dea_2800
雞腿和漢堡對應兩個產品等級體系結構
兩個等級結構中的KFC組成了一個產品族
兩個等級結構中的Mcdonalds組成了一個產品族
 
再好比,計算機中有文字處理軟件和圖像處理軟件
可是計算機有不一樣的操做系統平臺,好比Windows和Linux
image_5bea7dea_4e33
有文字處理和圖像處理兩種產品等級結構
兩個等級結構中的windows平臺下軟件組成了一個產品族
兩個等級結構中的Linux平臺下軟件組成了一個產品族 
 
因此說,不一樣類型的產品,就是不一樣的等級結構
水果是一個等級,蔬菜是一個等級,PC是一個等級
 
不一樣等級結構中,相關聯的一組功能就是一個產品族
相關聯的含義是有一些公共的限制約束或者特性
水果是一個等級,蔬菜是一個等級
熱帶水果和熱帶蔬菜,產地都是南方屬於熱帶地區 , 這就是一個產品族 
 
主板是一個等級,有多種廠家生產,好比華碩 戴爾
顯示器是一個等級,有多種廠家生產,好比華碩 戴爾
主板和顯式器能夠組成電腦的一部分
華碩主板和華碩顯示器都是華碩品牌的,是一個產品族
 
一個產品族中,有多少個產品,跟產品等級結構的個數是一致的
也就是說有多少種產品,一個產品族就有多少個

有CRUD四個產品等級,一個mysql產品族就有四個產品
有雞腿漢堡兩個產品等級,KFC產品族就有兩種產品
產品族就是一個產品類別中拿出來一個
因此就是一個類型有多少種,就是有多少個產品族
簡單理解就是:每一個類型來一個,就構成了一個產品族
 
想要使用工廠模式,首先就是要理清楚產品的等級結構
簡單工廠和工廠方法模式都只能建立一種等級結構的產品
若是想要建立多個等級結構的產品,你能夠藉助於多個工廠方法模式 
另外,若是有產品族的概念,你能夠考慮抽象工廠模式
須要特別關注是否有關聯和共同約束限制條件,也就是是否可以成爲產品族

意圖

提供一個建立一系列相關或者相互依賴對象的接口,而無需指定他們具體的類。
其實就是工廠方法模式中一個方法,建立一個類型,此處多個方法,建立多個類型,簡單理解就是這樣

結構

說完了產品等級結構和產品族的概念
咱們看下抽象工廠模式的結構
產品等級結構product
ProductA和ProductB
他們分別有對應的兩種類型的產品
ConcreteProductA1 和 ConcreteProductA2
ConcreteProductB1 和 ConcreteProductB2
抽象工廠角色Creator
Creator能夠建立ProductA和ProductB兩種抽象類型
他有兩個實現類工廠ConcreteCreator1和 ConcreteCreator2
具體的工廠ConcreteCreator
每個ConcreteCreator均可以生產一個產品族的產品
也就是ConcreteCreator1能夠生產ConcreteProductA1 和 ConcreteProductB1
 
image_5bea7dea_7a2

角色介紹

抽象工廠角色(Abstract Factory)
工廠方法的核心,與系統具體邏輯無關,一般是java接口或者抽象類
全部的具體的工廠都須要實現它,也就是上圖中的Creator
具體工廠角色(Concrete Factory)
直接接受客戶端程序請求,建立產品的實例,它能夠建立一個產品族的實例對象
抽象產品角色(Abstract Product)
爲一類產品對象聲明一個抽象表示
具體產品角色(Concrete Product)
定義一個被建立的具體的對象的類型,實現Abstract Product接口
 
相似工廠模式,具體的工廠角色能夠有多個,分別對應不一樣的產品族
有幾個產品族就會有幾個具體的工廠

示例代碼

有兩個產品等級結構 Fruit和Vegetable 也就是有水果和蔬菜兩種商品
假設有兩個商店,他們都提供水果和蔬菜
第一個商店提供的水果和蔬菜是蘋果和土豆
第二個商店提供的水果和蔬菜是橘子和白菜
也就是蘋果Apple和土豆Potato是一個產品族,由一個店鋪在賣
橘子Orange和大白菜Cabbage是一個產品族,由一個店鋪在賣
 
產品類Fruit以及Apple和Orange與工廠模式中示例代碼同樣
Vegetable表示蔬菜的抽象角色 Potato和Cabbage爲具體的蔬菜
有抽象工廠角色Factory
以及具體的工廠ConcreteFactory1  和 ConcreteFactory2
image_5bea7dea_6a2e
 
Fruit產品結構體系
package abstractFactory;
/**
* Created by noteless on 2018/10/9.
* Description:
*/
public interface Fruit {
String description();
}
package abstractFactory;
/**
* Created by noteless on 2018/10/9.
* Description:
*/
public class Apple implements Fruit {
@Override
public String description() {
return "apple";
}
}
package abstractFactory;
/**
* Created by noteless on 2018/10/9.
* Description:
*/
public class Orange implements Fruit {
@Override
public String description() {
return "Orange";
}
}
蔬菜產品結構體系
package abstractFactory;
/**
* Created by noteless on 2018/10/10.
* Description:
*/
public interface Vegetable {
String description();
}
package abstractFactory;
/**
* Created by noteless on 2018/10/10.
* Description:
*/
public class Potato implements Vegetable {
@Override
public String description() {
return "potato";
}
}
package abstractFactory;
/**
* Created by noteless on 2018/10/10.
* Description:
*/
public class Cabbage implements Vegetable {
@Override
public String description() {
return "cabbage";
}
}
工廠體系
package abstractFactory;
/**
* Created by noteless on 2018/10/9.
* Description:
*/
public interface Factory {
Fruit createFruit();
Vegetable createVegetable();
}
package abstractFactory;
/**
* Created by noteless on 2018/10/10.
* Description:
*/
public class ConcreateFactory1 implements Factory {
@Override
public Fruit createFruit() {
return new Apple();
}
@Override
public Vegetable createVegetable() {
return new Potato();
}
}
package abstractFactory;
/**
* Created by noteless on 2018/10/10.
* Description:
*/
public class ConcreateFactory2 implements Factory {
@Override
public Fruit createFruit() {
return new Orange();
}
@Override
public Vegetable createVegetable() {
return new Cabbage();
}
}
測試代碼
image_5bea7dea_1d33
 
 
能夠看得出來,下圖的形式中
只須要修改一行代碼,就能夠作到整個產品族的切換
image_5bea7deb_1e9b
 

使用場景

抽象工廠模式,是工廠模式的進一步抽象,能夠建立多個層級結構的產品
抽象工廠模式是將工廠模式拓展到他的產品族中,再也不是僅僅建立同一個產品,而是建立一個「族」
 
當系統中有多於一個的產品族,並且,系統在某刻只是消費其中某個產品族
也就是同屬於同一個產品族中的產品 會在一塊兒工做使用
這種場景下,比較適合抽象工廠模式
 
好比上面的例子,KFC和MCDonalds都有雞腿和漢堡,你去了KFC點餐那就是KFC的雞腿和漢堡
在KFC的「工廠」中,你調用雞腿和漢堡方法,得到雞腿和漢堡
 
若是你想要KFC的雞腿和MCDonalds的漢堡的話
你或許就是以下這種形式
Factory factory1 = new KFC();
KFC.雞腿;
Factory factory2 = new MCDonalds();
MCDonalds.漢堡;
若是是上面這種形式,須要兩個工廠,這樣也是能夠的
 
可是你應該避免胡亂隨便的產品等級結構混雜在一塊兒使用抽象工廠模式
之因此是建立了一個產品族,而不是任意八竿子打不着的產品中 , 是由於: 
若是產品等級結構變得更多,徹底沒有產品族的概念,好比水果、蔬菜、主板、顯示器
他們沒有產品族的概念,也更不會一塊兒使用,每種產品等級結構都下屬不少類型 
若是你像剛纔那樣KFC的雞腿和MCDonalds的漢堡 混搭的話
可能使用時,要建立多個工廠實例,每一個工廠到底生產什麼怕是本身都要混亂了,由於他們不是產品族,不成體系
還不如針對於每種產品等級結構一個單獨的工廠模式更加條理清晰,混搭徹底不符合單一職責原則
 
簡單想下兩種場景就能夠理解,好比海爾生產 冰箱洗衣機電視機微波爐等等
這些產品是同一個產品族,都是海爾XXX
哪怕有美的XX 西門子XX你都不會凌亂
可是若是A廠生產 蘋果 土豆 A主板 A顯示器 A顯卡
另外一個B廠生產橘子 白菜 B主板 B顯示器  B顯卡
另外一個C廠生產水蜜桃 茄子 C主板 C顯示器  C顯卡
當你須要蘋果白菜茄子A主板B顯示器C顯卡時會不會凌亂?
 
因此說,想要使用抽象工廠模式,必定要理清楚產品的層級結構體系以及產品族的概念
若是根本沒有產品族的概念,那麼不適合使用抽象工廠模式,你或許應該考慮多個不一樣的工廠方法模式
 
 

總結

與工廠方法模式 最直白的差別就在於:
抽象工廠方法能夠建立整個產品族,而工廠方法僅僅只能建立一種等級結構的產品
 
當你須要使用建立型模式的時候,若是你須要選擇工廠模式
那麼你應該最早考慮簡單工廠模式的形式,儘管他簡單到都不算是一種模式
若是簡單工廠模式不能勝任,產品等級結構過於複雜或者業務邏輯複雜,能夠考慮使用工廠方法模式
當產品等級結構不少,勢必會出現過多的工廠方法模式,也就是過多的工廠
那麼,若是這些產品中,可以組合成產品族的概念
則能夠應用抽象工廠模式
換句話說,當你須要建立不一樣的等級產品結構時,能夠考慮抽象工廠模式
從這一點看,抽象工廠模式不就是工廠模式的進一步延伸擴展嘛
 
抽象工廠的核心就在於抽象工廠角色,建立了全部類型的抽象產品
抽象工廠角色建立的就是一族的抽象產品角色,就是每種抽象產品角色建立一個
有多少個產品等級結構,他就有幾個方法建立對應的產品
因此必然,全部的實現類,都可以建立全部的產品類型,也就是建立的功能拓展到了產品族
前面的結構圖中,沒有畫紅色的兩條,畫上可能更好理解
image_5bea7deb_6e98
抽象工廠模式,與產品族的概念息息相關,必需要理解產品族的概念
產品族的概念並非嚴格的必須是同一品牌或者同一廠家這般強關聯
可是他們必須是有所關聯,也就是有共同的約束,好比在同一個操做系統上使用
只有你找到了某種關聯約束,能夠組織成產品族,也就是前文中的產品族的產品會一塊兒工做
那麼纔可使用抽象工廠,必定不要毫無關聯並且也不是一塊兒使用的產品等級結構放置在一塊兒
 
還要確保產品等級結構不會輕易發生變化,不然,時常變更那麼就意味着相關的工廠角色都須要頻繁的修改
是不能忍受的
 
若是結構圖中,去掉ProductB,這看起來是否是就是工廠模式?
因此說相對於工廠模式,抽象工廠模式最直觀的變化就是,將工廠的能力範圍擴展到了產品族上
一個工廠能夠建立同一個產品族的多種產品
image_5bea7deb_dab
擴展產品族
若是增長新的產品族時,也就是層級結構不變,可是每種產品結構下面具體產品變多了
好比Fruit下面多了一個Banana香蕉    Vegetable 下面多了個  Carrot 胡蘿蔔
這就須要增長一個具體的工廠,用於生產製造Banana 和 Carrot  
對於其餘的代碼,則不須要任何修改,知足開閉原則的要求
擴展產品等級結構
若是增長新的產品等級,好比Fruit Vegetable 又增長了一個肉類Meat 有羊肉牛肉等
怎麼辦?
那麼,咱們須要從抽象工廠角色Creator就開始增長一個方法用於建立肉類 Meat createMeat();
最頂級的抽象角色新增了方法,也就意味着全部的具體工廠,這些實現類,都須要隨之變更
擴展等級結構,顯然是致命的!徹底不符合開閉原則,這是他的一大缺點
 
看得出來,抽象工廠模式在擴展方面向產品族的擴展傾斜,給產品族的擴展提供了方便
可是在擴展產品等級結構時,卻沒法提供便利,因此適用於產品等級結構不太會變更的場景
相關文章
相關標籤/搜索