《大設》第十八篇之抽象工廠模式

来源:http://www.cnblogs.com/liaidai/archive/2016/11/14/6064018.html
-Advertisement-
Play Games

前言 國際慣例,本文仍然是在學習設計模式的路上所寫,希望對同樣在學習設計模式的童靴有點作用,大牛誤入的話還請給點寶貴意見,感激不盡。 另外最近好尷尬,公司外網全部給撤了,白天又沒有什麼事情乾,好TM尷尬,本來想著趁著最近沒事趕緊把設計模式看完寫完的,誰知道來這麼個事情,好尷尬,只能晚上加班寫了,白天 ...


前言

  國際慣例,本文仍然是在學習設計模式的路上所寫,希望對同樣在學習設計模式的童靴有點作用,大牛誤入的話還請給點寶貴意見,感激不盡。

  另外最近好尷尬,公司外網全部給撤了,白天又沒有什麼事情乾,好TM尷尬,本來想著趁著最近沒事趕緊把設計模式看完寫完的,誰知道來這麼個事情,好尷尬,只能晚上加班寫了,白天睡覺,只想說一句MDZZ.

模式解析

  好了,不廢話,今天繼續來學習設計模式中的抽象工廠模式,前面我們已經學習了簡單工廠模式和工廠方法模式,抽象工廠模式是工廠模式中的最後一個也是最複雜的一個。

  首先,我們來看一下百度百科對抽象工廠模式的定義:

  為創建一組相關或者相互依賴的對象提供一個介面,而且無需指定他們的具體類。

  什麼意思呢?就是說現在要創建一組對象,這組對象是相關的或者是相互依賴的,但是在創建這組對象的時候我們會提供一個介面,使用這個介面來創建這組對象,並且在創建對象時創建的並不是具體類而是抽象類。

  這麼說可能有的朋友還是不太明白,那麼我們來看一下抽象工廠的類圖:

  

  在類圖中有這麼幾種對象,分別是Creator、ConcreteCreator、Product、Product1,跟上面定義中的名詞的對應關係分別是:

  Creator對應上面的介面;

  Product對應要創建的一組對象;

  ConcreateCreator則是生產對象的工廠;

  並且定義中說到無需指定他們的具體類,那麼在創建對象時返回的一定是抽象類或者介面,很顯然就是Product而非他的實現類;

  上面定義也說了,類圖也給出了,下麵我們使用代碼的方式將上述的類圖展示出來:

  首先就是Creator介面,用來生成產品的介面:

public interface Creator {
    public ProductA createA();
    public ProductB createB();
}

  再者是介面的具體實現類,在實現類中來生成產品:

public class ProductFactoryA implements Creator{

    @Override
    public ProductA createA(){
        return new ProductA1();
    }
    
    @Override
    public ProductB createB(){
        return new ProductB1();
    }
}

public class ProductFactoryB implements Creator{

    @Override
    public ProductA createA(){
        return new ProductA2();
    }
    
    @Override
    public ProductB createB(){
        return new ProductB2();
    }
    
}

  最後是類圖右半部分的具體產品以及產品的實現類:

public interface ProductA {
    public void methodA();
}

public class ProductA1 implements ProductA{
    @Override
    public void methodA() {
        System.out.println("產品A系列中的A1產品");
    }
}

public class ProductA2 implements ProductA{

    @Override
    public void methodA() {
        System.out.println("產品A系列中的A2產品");
    }

}

  產品B及其實現類與產品A類似,在這裡就不再貼產品B的代碼了,下麵給出測試類及其測試結果:

public static void main(String[] args) {
    Creator creator = new ProductFactoryA();
    ProductA productA = creator.createA();
    ProductB productB = creator.createB();
    productA.methodA();
    productB.methodB();
    
    creator = new ProductFactoryB();
    productA = creator.createA();
    productB = creator.createB();
    productA.methodA();
    productB.methodB();
}

  測試結果如下所示:

  

  上面的示例代碼也看完了,是不是該說抽象工廠模式的優缺點,然後結束了?兄弟,你還是太年輕了啊,下麵我們先不說什麼優缺點,我們先來認識一個概念產品族,那麼什麼是產品族呢?

  所謂的產品族,是指位於不同產品等級結構中功能相關聯的產品組成的家族,MDZZ,剛知道了個產品族的名詞,怎麼又跑出來一個產品等級結構呢,接著往下看。

  我們還拿上面的例子來說,ProductA和ProductB就是兩個不同的產品等級結構,也就是說在抽象工廠模式中,有幾個產品系列就有幾個產品等級結構,然後什麼是產品族呢?其中的ProductA1和ProductB1就屬於一個產品族,另外的另個屬於另一個產品族。

  上面那麼說產品族可能不太好理解,我們舉個現實的例子,比如現在有兩種型號的車,分別是瑪莎拉蒂和勞斯萊斯,兩種車都有2.0和2.4兩種排量(說的不對別打我,畢竟窮屌絲就能意淫一下這種豪車了),那麼瑪莎拉蒂是一個產品等級結構,勞斯萊斯就是另外的一個產品等級結構,2.0排量的瑪莎拉蒂和2.0排量的勞斯萊斯是一個產品族,2.4排量的瑪莎拉蒂和2.4排量的勞斯萊斯是另外一個產品族,這樣來說的話大家應該好明白一點。

  有兄弟說,樓主樓主你費半天勁解釋一個產品族有啥作用啊?作用就是下麵要說的抽象工廠模式和工廠方法模式的區別,同樣我們先把工廠方法模式的類圖放出來:

  

  對比工廠方法模式和抽象工廠模式的類圖,大家有沒有發現什麼問題?對,其實就是工廠方法模式只有一個產品等級結構,但是抽象工廠模式可以有多個產品等級結構,可以說抽象工廠模式是工廠方法模式的擴展,只不過是針對多個產品等級結構的擴展。也就是說要區分抽象工廠模式和工廠方法模式最明顯的方式就是看產品等級結構的多少,如果只有一個,那麼肯定是工廠方法模式,如果多餘一個那麼肯定是抽象工廠模式沒跑了,下麵引用一個園子里左瀟龍大哥文章中一個真實的源碼的例子(原文地址)。

  什麼例子呢?就是我們常用的集合List,下麵的內容均來自上述左蕭龍文章中,特此聲明,我們首先可以下list介面的部分源碼:

package java.util;

public interface List<E> extends Collection<E> {
    
    Iterator<E> iterator();//一種產品

    Object[] toArray();

    <T> T[] toArray(T[] a);

    ListIterator<E> listIterator();//另外一種產品

    ListIterator<E> listIterator(int index);

}


LZ去掉了List介面中的很多方法,一是為了節省版面,另外是為了更清晰,我們主要關註iterator和listIterator方法,LZ在上面加了標註。

   其中ListIterator是Iterator的子介面,但歸根到底,它其實屬於另外一種產品,為什麼這麼說呢,ListIterator不是Iterator的子介面嗎,怎麼能算是另外一種產品呢?這是因為我們listIterator方法的返回類型是ListIterator,而不是Iterator,所以兩者的功能是不同的,比如ListIterator還可以向前移動。

  我們可以認為這兩個方法產生的一個是只能向後移動的迭代器,一個是可以前後移動的迭代器,這算是兩種產品,相當於上面的ProductA和ProductB。

 這個設計可以看做是一個抽象工廠模式,List介面定義了兩種生產不同產品的方法,這屬於兩個系列的產品,不過由於產品介面本身的繼承關係,兩者的實現類也會被做成繼承的關係。下麵給出上面提到的介面的UML圖。

這個圖看起來有點複雜,各位可以和上面標準的抽象工廠模式類圖對比一下,下麵LZ來解釋一下在抽象工廠模式當中,上述幾個類都代表的什麼角色。

1.List,是抽象工廠的角色,它有兩個製造產品的方法,iterator和listIterator,相當於Creator。

2.ListIterator和Iterator都是抽象產品,相當於ProductA和ProductB。其中ListIterator有兩個實現類,分別是AbstractList.ListItr和LinkedList.ListItr,相當於ProductA1和ProductA2。Iterator的實現類為AbstractList.Itr,相當於ProductB1,但是沒有B2。

3.LinkedList是其中一個具體的工廠類,相當於ConcreteCreator1,實現抽象工廠List,它製造的兩個具體產品分別是LinkedList.ListItr和AbstractList.Itr。

4.同樣的,ArrayList也是一個具體的工廠類,相當於ConcreteCreator2,實現抽象工廠List,它製造的兩個具體產品分別是AbstractList.ListItr和AbstractList.Itr。

 結合上一章工廠方法模式,我們來分析一下工廠方法模式和抽象工廠模式二者的關係。

Iterable介面是List的父介面,所以它只負責一個產品Iterator的製造,所以是工廠方法模式,而List介面擴展了Iterable介面,又添加了一個製造產品的方法,即又添加了一個系列的產品,所以就成為了抽象工廠模式。

  沒分析過JDK源碼的人還是很少能分析的這麼透徹的吧,我這源碼都沒看過的人就不發表評論了,只是感覺好牛逼,轉載到自己文章中,省的哪天找不到,那就咖喱給給了啊。

  真實的源碼例子也給大家找來了,我們下麵來對比一下三個工廠模式,從最簡單的簡單工廠模式到工廠方法模式再到最後的抽象工廠模式,這三者都是工廠模式,都屬於創建型設計模式,在形式和特點上是十分相似的,但是簡單工廠模式是違反開閉原則的,但是在工廠方法模式中彌補了這一點,但是工廠方法模式只有一個產品等級結構,使用抽象工廠模式也可以彌補,可以說這三個設計模式是層層遞進的關係,但是在本質上著三者是沒有太大的區別的,都是為了生成對象,至於選擇哪個模式就要看你的業務了,還是那句話,模式是死的,人是活的,靈活的選擇模式或者準確的來說靈活的使用設計模式是更重要的。

  好了,今天這篇就到這裡了,優缺點使用場景什麼的說不說都一樣,下篇再見,下麵是最受觀眾喜愛的參考文章列表。

參考文章

  1. http://www.cnblogs.com/zuoxiaolong/p/pattern6.html
  2. http://blog.csdn.net/zhengzhb/article/details/7359385/

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文出自http://www.cnblogs.com/scoter2008 1、強大的官方文檔 2、按步驟來,先更新yum源,這裡用163的源 3、更新系統 4、如果遇到問題:Delta RPMs disabled because /usr/bin/applydeltarpm not install ...
  • ipcs 1. 命令格式 ipcs [resource-option] [output-format] ipcs [resource-option] -i id 2. 命令功能 提供IPC設備的信息 3. 使用方法 resource選項: ipcs -m 查看系統共用記憶體信息 ipcs -q 查看系 ...
  • 1.命令格式 find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression] 2. 命令功能 在文件目錄層級中查找文件並做相應的處理 3. 命令選項 -name finename 按照文件名查找文件,文件名可使用通配符 -per ...
  • C# 知識回顧 - Event 事件 段子:內容與主題無關 很多年輕人會問到:看什麼書好呢?這是比較專業的回答: 第一階段:《數據結構》,《軟體工程》,《C語言》,《C++》,《Java》,《設計模式》。。。第二階段:《莫生氣》,《佛經》,《老子》,《思想政治》,《論持久戰》第三階段:《頸椎病康復指 ...
  • 鑒於框架的使用者越來越多,文檔太少,不少用戶反映框架的入門門檻太高。好吧,再辛苦下,抽時間寫教程吧! ...
  • 本文介紹.Net Core下用第三方ZKWeb.System.Drawing實現驗證碼功能。 通過測試的系統: Windows 8.1 64bit Ubuntu Server 16.04 LTS 64bit Fedora 24 64bit CentOS 7.2 64bit 可以實現以下功能: Ope... ...
  • ...
  • 求一個數兩位數的個位數,十位數及百位數: int num = 53; int g = num % 10; //個位 int s = (num / 10) % 10; //十位 int b = (num / 100); //百位 下麵是用java寫的一個一般般的 拆分整數的案例 值得大伙研究研究,趣味 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...