悟空模式-java-抽象工廠模式

来源:http://www.cnblogs.com/tirion/archive/2017/09/19/7552121.html
-Advertisement-
Play Games

【一朝,王母娘娘設宴,大開寶閣,瑤池中做蟠桃勝會】 有一天,王母娘娘要在瑤池辦party,就需要準備大量的食材。要知道,天上的神仙也分三六九等,九曜星、五方將、二十八宿、四大天王、十二元辰、五方五老、普天星相、河漢群神等等,不同等級的神仙在宴會中吃的東西也不一樣。 為了方便管理,我們把神仙分為低級神 ...


【一朝,王母娘娘設宴,大開寶閣,瑤池中做蟠桃勝會】

有一天,王母娘娘要在瑤池辦party,就需要準備大量的食材。要知道,天上的神仙也分三六九等,九曜星、五方將、二十八宿、四大天王、十二元辰、五方五老、普天星相、河漢群神等等,不同等級的神仙在宴會中吃的東西也不一樣。

為了方便管理,我們把神仙分為低級神仙、中級神仙和高級神仙,不同等級的神仙將領取到對應等級的食物,所以就有了低級神仙食物、中級神仙食物和高級神仙食物。

在前面的悟空模式-java-普通工廠模式悟空模式-java-工廠方法模式中都介紹了低級蟠桃(三千年)、中級蟠桃(六千年)和高級蟠桃(九千年),雖然是蟠桃盛會,但也總不能光吃蟠桃,所以由兜率宮拿出了一批仙丹,分為低級仙丹(煉三三得九天)、中級仙丹(煉七七四十九天)和高級仙丹(煉九九八十一天)。

以上,就是我們本次演示抽象工廠模式所需要的產品元素。

在前面我們說過,當產品越來越多,會使得工廠越來越難管理,要麼工廠的數量越來越多,要麼工廠本身越來越複雜,所以,這裡介紹了抽象工廠模式,用於產生較為複雜的產品結構下的工廠,它與工廠方法最基本的區別是抽象工廠模式能夠創建不同種類的產品,也就能夠更加方便地基於抽象的概念管理一大堆複雜的產品對象。

首先我們介紹兩個概念:產品族與產品等級。

所謂產品族,就是由功能相關聯的不同種類產品組成的家族,比如我們最終所需要的低級神仙食物,它是由低級蟠桃與低級仙丹組成的。而產品等級就是對於某一種類的產品,內部劃分的等級結構,如蟠桃內部被劃分為低級、中級與高級,產品等級是面向同一種類的產品的內部區別描述。

在一開始,我們需要創建一個抽象工廠,這個抽象工廠中描述了每個具體工廠需要提供哪些實現。然後針對每一個產品族創建一個工廠,用於統一創建不同類型的產品。類圖如下:

從圖中可以看到,不同等級的產品交給了不同的工廠去創建,用戶只需要調用自己的目標產品族對應的工廠,獲取最終的產品族即可,至於這個產品系列內部結構如何變化,用戶並不需要關心。接下來是具體的實現:

蟠桃

package com.tirion.design.abstraction.factory;

public interface FlatPeach {

    void printLevel();

    void printCycleTime();
}

低級蟠桃

package com.tirion.design.abstraction.factory;

public class LowLevelFlatPeach implements FlatPeach {

    LowLevelFlatPeach(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("低級蟠桃");
    }

    @Override
    public void printCycleTime() {
        System.out.println("三千年一熟");
    }

}

中級蟠桃

package com.tirion.design.abstraction.factory;

public class MiddleLevelFlatPeach implements FlatPeach {

    MiddleLevelFlatPeach(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("中級蟠桃");
    }

    @Override
    public void printCycleTime() {
        System.out.println("六千年一熟");
    }

}

高級蟠桃

package com.tirion.design.abstraction.factory;

public class HighLevelFlatPeach implements FlatPeach {

    HighLevelFlatPeach(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("高級蟠桃");
    }

    @Override
    public void printCycleTime() {
        System.out.println("九千年一熟");
    }

}

仙丹

package com.tirion.design.abstraction.factory;

public interface Elixir {

    void printLevel();

    void printCycleTime();
}

低級仙丹

package com.tirion.design.abstraction.factory;

public class LowLevelElixir implements Elixir {

    LowLevelElixir(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("低級仙丹");
    }

    @Override
    public void printCycleTime() {
        System.out.println("煉三三得九天");
    }

}

中級仙丹

package com.tirion.design.abstraction.factory;

public class MiddleLevelElixir implements Elixir {

    MiddleLevelElixir(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("中級仙丹");
    }

    @Override
    public void printCycleTime() {
        System.out.println("煉七七四十九天");
    }

}

高級仙丹

package com.tirion.design.abstraction.factory;

public class HighLevelElixir implements Elixir {

    HighLevelElixir(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("高級仙丹");
    }

    @Override
    public void printCycleTime() {
        System.out.println("煉九九八十一天");
    }

}

抽象工廠-神仙食物工廠

package com.tirion.design.abstraction.factory;

public interface XianFoodFactory {

    FlatPeach prepareFlatPeach();

    Elixir prepareElixir();

}

低級神仙食物工廠

package com.tirion.design.abstraction.factory;

public class LowLevelXianFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new LowLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return new LowLevelElixir();
    }


}

中級神仙食物工廠

package com.tirion.design.abstraction.factory;

public class MiddleLevelXianFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new MiddleLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return new MiddleLevelElixir();
    }


}

高級神仙食物工廠

package com.tirion.design.abstraction.factory;

public class HighLevelXianFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new HighLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return new HighLevelElixir();
    }


}

王母娘娘-調用者

package com.tirion.design.abstraction.factory;


public class TheQueenMother {

    public static void prepareXianFood(XianFoodFactory xianFoodFactory) {
        xianFoodFactory.prepareFlatPeach();
        xianFoodFactory.prepareElixir();
    }

    public static void main(String[] args) {
        System.out.println("準備低級神仙食物...");
        TheQueenMother.prepareXianFood(new LowLevelXianFoodFactory());
        System.out.println("準備中級神仙食物...");
        TheQueenMother.prepareXianFood(new MiddleLevelXianFoodFactory());
        System.out.println("準備高級神仙食物...");
        TheQueenMother.prepareXianFood(new HighLevelXianFoodFactory());
    }
}

代碼執行結果

準備低級神仙食物...
三千年一熟
低級蟠桃
煉三三得九天
低級仙丹
準備中級神仙食物...
六千年一熟
中級蟠桃
煉七七四十九天
中級仙丹
準備高級神仙食物...
九千年一熟
高級蟠桃
煉九九八十一天
高級仙丹

使用了抽象工廠模式之後,在面對複雜的宴會菜單對象時,王母娘娘不需要關心天宮的御廚如何搭配食物,只需要下達命令要求御廚準備不同等級的食物套餐就可以了。

每個具體工廠只需要創建自己負責的產品,這符合單一職責原則。

具體工廠返回的產品是產品的抽象而不是具體,所以符合依賴導致原則。

關於開閉原則,抽象工廠模式是一個比較典型的例子。

我們在使用中可以發現,如果要添加一個新的產品族,比如王母娘娘專享食物套餐,套餐內容是高級蟠桃,而並不需要吃仙丹(王母娘娘吃仙丹已經沒啥用了),那麼我們只需要增加一個TheQueenMotherFoodFactory,然後在內部添加具體的實現即可,並不需要更改其他任何類,很完美地符合了開閉原則。

王母娘娘食物工廠

package com.tirion.design.abstraction.factory;

public class TheQueenMotherFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new HighLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return null;
    }


}

但是如果某一天,鎮元大仙上供了一批人參果,王母娘娘一高興,把人參果也作為宴會的一道主菜,那麼就麻煩了:不僅僅抽象工廠XianFoodFactory要增加人參果的介面,它的所有實現都要增加相應的介面實現,整個體系才能繼續運轉下去。這時候,抽象工廠模式又不符合開閉原則了。

根據以上描述我們可以得出,對於抽象工廠模式,增加產品族符合開閉原則,增加產品種類則不符合開閉原則,也就是說抽象工廠模式具備開閉原則的傾斜性。

註意:抽象工廠模式並不是比工廠方法模式更加高級的模式,而是為了適應不同的業務變化情況而做出的不同應對,繼而產生的不同解決方案而已。

抽象工廠模式的使用情景:

1.系統中存在多個產品族,用戶只關心產品族,也就是只關心最終結果

2.屬於同一產品族的產品相互之間具有關聯關係,它們是被組合在一起使用的

抽象工廠模式遵循的設計原則:

1.依賴倒置原則(客戶端依賴的是產品抽象而不是具體產品)

2.迪米特法則

3.里氏替換原則

4.介面隔離原則(使用了多個相互隔離的介面,降低了耦合度)

5.單一職責原則(每個工廠只要負責創建自己對應產品族的產品)

6.開閉原則(具有傾斜性,支持新增產品族,但不支持新增產品類型)

關於抽象工廠模式的介紹就到這裡,你可以將它記憶為蟠桃宴會模式

如果你認為文章中哪裡有錯誤或者不足的地方,歡迎在評論區指出,也希望這篇文章對你學習java設計模式能夠有所幫助。轉載請註明,謝謝。

更多設計模式的介紹請到悟空模式-java設計模式中查看。


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

-Advertisement-
Play Games
更多相關文章
  • ptyhon版本 Python 3.5.4 支持中文直接輸入和顯示,ptyhon2.x 中文支持需要轉碼 編輯器:pycharm hello world 註釋 單行註釋:用#作為單行註釋 多行註釋:使用3個單引號(''')或者3個雙引號(""")圍起來的內容將被註釋。如下 變數(var) 變數命名規 ...
  • 題目描述 形如2P-1的素數稱為麥森數,這時P一定也是個素數。但反過來不一定,即如果P是個素數,2P-1不一定也是素數。到1998年底,人們已找到了37個麥森數。最大的一個是P=3021377,它有909526位。麥森數有許多重要應用,它與完全數密切相關。 任務:從文件中輸入P(1000<P<310 ...
  • 上次我們講了Java中的一些基本的語法;今天我們就講一點內容,來說說Java中的方法和方法重載以及需要註意的一些地方; 方法: Java的方法類似與其他語言的函數,是一段用來完成特定功能的代碼片段, 聲明格式: [修飾符1 修飾符2 ....] ,返回值類型 方法名 (形式參數列表) { Java語 ...
  • 要理解select.select模塊其實主要就是要理解它的參數, 以及其三個返回值。select()方法接收並監控3個通信列表, 第一個是所有的輸入的data,就是指外部發過來的數據,第2個是監控和接收所有要發出去的data(outgoing data),第3個監控錯誤信息在網上一直在找這個sele ...
  • 由於最近新上的項目很多模塊沒有做數據緩存,大量的請求都會到資料庫去查詢,為了減輕資料庫的壓力以及提高網站響應速度,所以在這裡採用了spring 提供的註解+redis實現對數據的緩存,主要針對非熱點數據,例如 省市,銀行卡列表等做緩存,在這裡主要是查詢做一個緩存實例。 pom.xml (加入spri ...
  • 序 好久沒寫設計模式了,自從寫了兩篇之後,就放棄治療了,主要還是工作太忙了啊(藉口,都是藉口),過完年以後一直填坑,填了好幾個月,總算是穩定下來了,可以打打醬油了。 為什麼又重新開始寫設計模式呢?學習使我快樂啊(我裝逼起來我自己都害怕),其實主要是最近填坑的時候看源代碼有點暈,很多代碼不知道他們為什 ...
  • 單例,故名思議,一個只能創建一個實例的類。 單例被廣泛應用於Spring的bean(預設)、線程池、資料庫連接池、緩存,還有其他一些無狀態的類如servlet。 一個沒必要多例的類實現了單例可以節約空間(顯而易見),節省資源(線程、資料庫連接)。 單例模式有這麼多好處,那我們來實現它吧,首先想到的是 ...
  • 報錯 原因 action與result-type順序搞錯了 package里元素必須按照一定的順序排列: result-types interceptors default-interceptor-ref default-action-ref default-class-ref global-res ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...