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

来源:https://www.cnblogs.com/noteless/archive/2018/11/13/9952480.html
-Advertisement-
Play Games

抽象工廠模式簡介,介紹了抽象工廠模式意圖,結構,產品族以及產品等級的概念,並且提供了代碼示例java版抽象工廠模式,抽象工廠模式與工廠模式的對比差異 ...


  抽象工廠模式是工廠方法模式的進一步抽象   在工廠模式中,客戶端程式依賴(消費)一種抽象產品角色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(); 最頂級的抽象角色新增了方法,也就意味著所有的具體工廠,這些實現類,都需要隨之變動 擴展等級結構,顯然是致命的!完全不符合開閉原則,這是他的一大缺點   看得出來,抽象工廠模式在擴展方面向產品族的擴展傾斜,給產品族的擴展提供了方便 但是在擴展產品等級結構時,卻無法提供便利,所以適用於產品等級結構不太會變動的場景      
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • div、h1或p元素常常被稱為塊級元素。這意味著這些元素顯現為一塊內容,即“塊框”。與之相反,span和h3等元素稱為“行內元素”,這是由於它們的內容顯現內行中,即“行內框”。 在這種狀況下,這個框稱為無名塊框,由於它不與專門界說的元素相關聯。 塊級元素的文本行也會發作相似的狀況。假設有一個包括三行 ...
  • 1、flex佈局 1.1 容器指定為flex佈局 .box{display: flex;} 1.2 行元素指定flex佈局 .box{display:inline-flex} 2、容器的屬性 2.1、flex-direction 2.2、flex-wrap 2.3、flex-flow 2.4、jus ...
  • *.3gpp audio/3gpp, video/3gpp 3GPP Audio/Video*.ac3 audio/ac3 AC3 Audio*.asf allpication/vnd.ms-asf Advanced Streaming Format*.au audio/basic AU Audio ...
  • 前幾天給了個需求對瀏覽器網頁進行截圖,把網頁統計數據圖形表等截圖保存至用戶本地。 首先對於網頁截圖,我用的是canvas實現,獲取你需要截圖的模塊的div,從而使用canvas對你需要的模塊進行截圖。 我們先來引入canvas的js文件,js文件獲取地址官網主頁:http://html2canvas ...
  • 項目中遇到的問題,需要表頭固定,給表主體設置滾動條。搜了很多種方法,bootstrap table也研究了一下。 下麵是我們使用的方法。 表頭放在div1中,表主體放在div2中,給div2設置固定高度,加樣式overflow:auto,這樣在數據多的時候會出現滾動條,數據少的時候滾動條會消失。 如 ...
  • <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title><!-- 步驟分析 1.確定事件:點擊事件:onclick事件 2.事件要觸發函數selectOne 3.selectOne要做一些操作 ...
  • @media screen and (max-width: 300px) { //當視口寬度小於等於300px時生效 } max-width 相當於 <= @media screen and (min-width: 300px) { //當視口寬度大於等於300px時生效 } max-width 相 ...
  • 本文作者:陳明傑(sandyskies) Tars是騰訊從2008年到今天一直在使用的後臺邏輯層的統一應用框架,目前支持C++,Java,PHP,Nodejs,Golang語言。該框架為用戶提供了涉及到開發、運維、以及測試的一整套解決方案,幫助一個產品或者服務快速開發、部署、測試、上線。 它集可擴展 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...