23種設計模式-創建型模式-抽象工廠

文章目錄

  • 簡介
  • 場景
  • 問題
    • 1. 風格一致性失控
    • 2. 對象創建硬編碼
    • 3. 產品族管理失效
  • 解決
  • 總結

簡介

抽象工廠是一種創建型設計模式,可以生成相關對象系列,而無需指定它們的具體類。

場景

假設你正在寫一個家具店模擬器。
你的代碼這些類組成:

  1. 相關產品系列,例如:椅子 + 沙發 + 咖啡桌。
  2. 此系列有多種風格。例如,椅子 + 沙發 + 咖啡桌系列有以下風格:現代、維多利亞、裝飾藝術。

在這里插入圖片描述
你需要一種方法來創建家具對象,確保它們與同一風格的其他對象相匹配。如果客戶收到風格不匹配的家具,他們就會非常生氣。

在這里插入圖片描述
另外,在向程序添加新產品或產品系列時,你也不想更改現有代碼。
按照慣例,大家一開始會怎么實現?

// 直接實例化具體家具類導致風格混雜
class Client {public void createLivingRoom() {// 混合使用不同風格組件(致命錯誤)Chair modernChair = new ModernChair();Sofa victorianSofa = new VictorianSofa();CoffeeTable artDecoTable = new ArtDecoCoffeeTable();modernChair.sit();victorianSofa.lieDown();artDecoTable.placeMagazine();}
}// 具體產品實現
class ModernChair extends Chair {public void sit() { System.out.println("Modern chair sitting"); } 
}class VictorianSofa extends Sofa {public void lieDown() { System.out.println("Victorian sofa relaxing"); }
}class ArtDecoCoffeeTable extends CoffeeTable {public void placeMagazine() { System.out.println("ArtDeco table placement"); }
}

問題

1. 風格一致性失控

客戶端直接創建不同風格的對象(現代椅子+維多利亞沙發)
╭── 問題場景 ──╮
用戶訂單要求"維多利亞風格客廳"時:
┌─────────────────┬──────────────────────┐
│ 預期組合 │ 實際可能創建的組合 │
├─────────────────┼──────────────────────┤
│ VictorianChair │ VictorianChair │
│ VictorianSofa │ ModernSofa ←不匹配 │
│ VictorianTable │ ArtDecoTable ←災難性 │
└─────────────────┴──────────────────────┘
結果:客戶收到風格沖突的家具套裝

2. 對象創建硬編碼

每當新增風格時(如新增ArtDeco),強制修改所有客戶端代碼


// 新增風格場景產生連鎖修改
class Client {// 必須添加新分支判斷public void createSet(String style) {if ("ArtDeco".equals(style)) { // 破壞開放封閉原則chair = new ArtDecoChair(); // 需要新增多個類引用sofa = new ArtDecoSofa();}}
}

3. 產品族管理失效

缺乏統一約束機制,易出現類型錯誤

// 錯誤將現代餐桌與維多利亞椅組合(類型系統無法阻止)
FurnitureSet set = new FurnitureSet(new ModernChair(),new VictorianDiningTable() // 應該拋出異常但現有代碼無法約束
);

解決

抽象工廠模式建議的第一件事就是明確聲明產品系列中每個不同產品的接口(例如,椅子、沙發或咖啡桌)。然后,讓所有風格的產品都實現這些接口。例如,所有風格的椅子都可以實現 Chair 接口;所有風格的咖啡桌都可以實現 CoffeeTable 接口,等等。

在這里插入圖片描述

// 接口約束產品規格
public interface Chair {void sit();
}public interface Sofa {void lieDown();
}public interface CoffeeTable {void placeItem();
}
// 確保現代系列組件統一
public class ModernChair implements Chair {@Overridepublic void sit() { System.out.println("Modern chair designed seating"); }
}public class ModernSofa implements Sofa {@Overridepublic void lieDown() { System.out.println("Modern sofa clean lines design"); }
}public class ModernCoffeeTable implements CoffeeTable {@Overridepublic void placeItem() { System.out.println("Modern geometric table surfaces"); }
}// 保證維多利亞風格一致性
public class VictorianChair implements Chair {@Overridepublic void sit() { System.out.println("Classic carved wood chair"); }
}public class VictorianSofa implements Sofa {@Overridepublic void lieDown() { System.out.println("Antique fabric sofa"); }
}public class VictorianCoffeeTable implements CoffeeTable {@Overridepublic void placeItem() { System.out.println("Ornate marble-top table"); }
}

下一步是聲明抽象工廠(接口),其中包含特定產品系列所有產品的創建方法列表(例如,createChair、createSofa 和 createCoffeeTable)。這些方法必須返回我們之前定義的抽象產品類型接口:Chair、Sofa、CoffeeTable 等等。對于產品的每種風格,我們基于 AbstractFactory 接口創建一個單獨的工廠類。這個工廠類是返回特定類型產品的類。例如,ModernFurnitureFactory 只能創建 ModernChair、ModernSofa 和 ModernCoffeeTable 對象。
在這里插入圖片描述

public interface FurnitureFactory {Chair createChair();Sofa createSofa();CoffeeTable createCoffeeTable();
}// 現代風格產品線工廠
public class ModernFactory implements FurnitureFactory {@Overridepublic Chair createChair() { return new ModernChair(); }@Overridepublic Sofa createSofa() { return new ModernSofa(); }@Overridepublic CoffeeTable createCoffeeTable() { return new ModernCoffeeTable(); }
}// 維多利亞風格產品線工廠
public class VictorianFactory implements FurnitureFactory {@Overridepublic Chair createChair() { return new VictorianChair(); }@Overridepublic Sofa createSofa() { return new VictorianSofa(); }@Overridepublic CoffeeTable createCoffeeTable() { return new VictorianCoffeeTable(); }
}

客戶端代碼必須通過抽象接口來和工廠、產品協作。這樣就可以更改傳給客戶端代碼的工廠的類型以及客戶端代碼接收的產品風格,而不破壞實際的客戶端代碼。
假設客戶希望工廠生產一把椅子。客戶不必知道工廠的類別,也不必關心它得到的椅子是什么類型。無論是現代風格還是維多利亞風格的椅子,客戶都必須使用抽象Chair接口以相同的方式處理所有椅子。唯一知道的是sitOn方法。此外,無論返回哪種椅子,它總是與同一工廠對象生產的沙發或咖啡桌風格相匹配。

public class FurnitureStore {private FurnitureFactory factory;// 動態綁定具體工廠public FurnitureStore(FurnitureFactory factory) {this.factory = factory;}public void showcaseSet() {Chair chair = factory.createChair();Sofa sofa = factory.createSofa();CoffeeTable table = factory.createCoffeeTable();System.out.println("展示完整風格套件:");chair.sit();sofa.lieDown();table.placeItem();}
}// 使用示例
public class Main {public static void main(String[] args) {// 創建現代風格商店FurnitureStore modernStore = new FurnitureStore(new ModernFactory());modernStore.showcaseSet();// 創建維多利亞風格商店FurnitureStore victorianStore = new FurnitureStore(new VictorianFactory());victorianStore.showcaseSet();}
}

還有一件事需要明確:如果客戶端只接觸抽象接口,那是什么創建了實際的工廠對象(即new ModernFactory())?通常,應用程序在初始化階段創建一個具體的工廠對象。在這之前,應用程序必須根據配置或環境設置選擇工廠類型。

總結

在這里插入圖片描述

  1. 抽象產品(Abstract Prod-uct):構成所有產品的一組接口。
  2. 具體產品(Con-crete Prod-uct):抽象產品的多種不同類型實現。所有風格產品(維多利亞/現代)都必須實現相應的抽象產品(椅子/沙發)。
  3. 抽象工廠(Abstract Fac-to-ry)接口:聲明了一組創建各種抽象產品的方法。
  4. 具體工廠(Con-crete Fac-to-ry):實現抽象工廠的產品創建方法。每個具體工廠都對應特定風格的產品,且只能創建這一種風格的產品。
  5. 盡管具體工廠會對具體產品進行初始化,它的創建方法必須返回相應的抽象產品。只有這樣,使用工廠類的客戶端代碼就不會與工廠創建的特定風格產品耦合。客戶端(Client)只需通過抽象接口調用工廠和產品對象,就可以跟任何具體工廠/產品進行交互。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/74312.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/74312.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/74312.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

案例:網絡命名空間模擬隔離主機場景

場景描述 假設我們需要在同一臺物理機上模擬兩臺獨立的主機(Host A 和 Host B),它們分別位于不同的網絡命名空間中,并通過虛擬以太網對(veth pair)進行通信。目標是展示網絡命名空間的隔離性和跨命名空間的…

新聞發布時間抽取(二)

1. 再論抽取方法 在前一期實驗中,對gne組件進行分析和完善,對三種時間抽取的方法進行了實驗對比。 在對抽取結果進行個例分析的過程中,我發現此前實驗存在幾個問題: 抽取的1000篇新聞存在一定的重復,經過ID去重大約減…

算法基礎——棧

一、棧的概念 棧是?種只允許在?端進?數據插?和刪除操作的線性表。 進?數據插?或刪除的?端稱為棧頂,另?端稱為棧底。不含元素的棧稱為空棧。進棧就是往棧中放?元素,出棧就是將元素彈出棧頂。 二、棧的模擬實現 1. 創建 本質還是線性表&#…

Android11至15系統定制篇

Android 11至15系統定制核心要點解析 一、Android 11關鍵定制特性 ?分區存儲強制化? 公共目錄(如Downloads、Pictures)與應用專屬目錄分離,應用更新后無法通過requestLegacyExternalStorage繞過限制?1。需申請MANAGE_EXTERNAL_STORAGE權限…

macOS 使用 enca 識別 文件編碼類型(比 file 命令準確)

文章目錄 macOS 上安裝 enca基本使用起因 - iconv關于 enca安裝 Encaenca & enconv 其它用法 macOS 上安裝 enca brew install enca基本使用 enca filepath.txt示例 $ enca 動態規劃算法.txt [0] Simplified Chinese National Standard; GB2312CRLF line terminat…

線段樹與掃描線 —— 詳解算法思想及其C++實現

目錄 一、線段樹(Segment Tree) 基本概念 結構 操作 示例代碼 二、掃描線(Sweep Line) 基本概念 應用場景 示例代碼(矩形面積并集) 三、總結 一、線段樹(Segment Tree) 基本…

匯編代碼中嵌入回調函數的優化說明

一、概述 在 PowerPC 的匯編代碼中,我們需要實現調用 C 函數(例如回調函數),并傳遞參數。本文將詳細介紹如何通過一系列步驟完成這一目標,包括代碼示例和詳細的注釋。 二、調用 C 函數的基本步驟及代碼 1. 保存工作寄…

Uni-App 雙欄聯動滾動組件開發詳解 (電梯導航)

本文基于提供的代碼實現一個左右聯動的滾動組件&#xff0c;以下是詳細的代碼解析與實現原理說明&#xff1a; <!--雙欄聯動滾動組件 - 技術解析功能特性&#xff1a;1. 左側導航欄與右側內容區雙向聯動2. 自適應容器高度3. 平滑滾動定位4. 動態內容位置計算 --> <te…

軟考復習-傳輸介質與編碼

傳輸介質 雙絞線 傳輸距離100一200m&#xff0c;即網線&#xff0c;有多種分類 UTP非屏蔽雙絞線 STP屏蔽雙絞線 線序標準有兩種為&#xff1a; T568A標準&#xff1a;綠白、綠、橙白、藍、藍白、橙、棕白、棕 T568B標準&#xff1a;橙白、橙、綠白、藍、藍白、綠、棕白、…

論文閱讀筆記:Denoising Diffusion Probabilistic Models (3)

論文閱讀筆記&#xff1a;Denoising Diffusion Probabilistic Models (1) 論文閱讀筆記&#xff1a;Denoising Diffusion Probabilistic Models (2) 論文閱讀筆記&#xff1a;Denoising Diffusion Probabilistic Models (3) 4、損失函數逐項分析 可以看出 L L L總共分為了3項…

PyTorch 面試題及參考答案(精選100道)

目錄 PyTorch 的動態計算圖與 TensorFlow 的靜態計算圖有何區別?動態圖的優勢是什么? 解釋張量(Tensor)與 NumPy 數組的異同,為何 PyTorch 選擇張量作為核心數據結構? 什么是 torch.autograd 模塊?它在反向傳播中的作用是什么? 如何理解 PyTorch 中的 nn.Module 類?…

#C8# UVM中的factory機制 #S8.1.4# 約束的重載

今天,復習一下《UVM實戰》一書中的 關于約束的重載 章節學習。 一 問題引導 文件:src/ch8/section8.1/8.1.2/rand_mode/my_transaction.sv4 class my_transaction extends uvm_sequence_item; …17 constraint crc_err_cons{18 crc_err == 1b0;19 }20 const…

空調遙控器低功耗單片機方案

RAMSUN空調遙控器采用先進的32位低功耗單片機作為核心控制器&#xff0c;通過優化軟件算法和硬件設計&#xff0c;實現了空調遙控器的低功耗運行。單片機集成了多種功能模塊&#xff0c;包括紅外發射、按鍵掃描、電源管理等&#xff0c;有效降低了整體功耗。同時&#xff0c;該…

結構型——代理模式

結構型——代理模式 代理模式指的是通過創建一個代理來控制對原始對象的訪問。代理在客戶端與實際對象之間充當“中介” 特點 訪問控制&#xff1a;代理對象可以控制對實際對象的訪問&#xff0c;從而實現對訪問權限的控制。延遲加載&#xff1a;代理對象可以在實際對象被調…

【算法】常見排序算法(插入排序、選擇排序、交換排序和歸并排序)

文章目錄 前言一、排序概念及常見排序算法框圖1.排序概念2.常見排序算法框圖 二、實現比較排序算法1.插入排序1.1 直接插入排序1.2 希爾排序 2.選擇排序2.1 直接選擇排序2.2 堆排序 3.交換排序3.1 冒泡排序3.2 快速排序3.2.1 hoare版本3.2.2 挖坑法3.2.3 lomuto前后指針 3.3 快…

Go語言分布式鎖實戰:dlock助力構建高并發穩定系統

在構建分布式系統時&#xff0c;一個常見且棘手的問題便是資源競爭和數據一致性問題。分布式鎖作為一種常用的解決方案&#xff0c;在多個進程或節點之間協調訪問共享資源時顯得尤為重要。今天&#xff0c;我們將介紹一款分布式鎖庫——dlock&#xff0c;并通過詳細的使用示例帶…

算法方法快速回顧

&#xff08;待修改&#xff09; 目錄 1. 雙指針2. 滑動窗口理論基礎 3. 二分查找3. 二分查找理論基礎 4. KMP5. 回溯算法6. 貪心算法7. 動態規劃7.1. 01背包7.2. 完全背包7.3. 多重背包 8. 單調棧9. 并查集10. 圖論10.1. 廣度優先搜索&#xff08;BFS&#xff09;10.2. 深度優…

深度學習:讓機器學會“思考”的魔法

文章目錄 引言&#xff1a;從“鸚鵡學舌”到“舉一反三”一、深度學習是什么&#xff1f;1. 定義&#xff1a;機器的“大腦”2. 核心思想&#xff1a;從數據中“悟”出規律 二、深度學習的“大腦”結構&#xff1a;神經網絡1. 神經元&#xff1a;深度學習的基本單元2. 神經網絡…

電動自行車/電動工具鋰電池PCM方案--SH367003、SH367004、SH79F329

在消費電子系統中&#xff0c;如手機電池包&#xff0c;筆記本電腦電池包等&#xff0c;帶有控制IC、功率MOSFETFE管以及其他電子元件的電路系統稱為電池充放電保護板Protection Circuit Module &#xff08;PCM&#xff09;&#xff0c;而對于動力電池的電池管理系統&#xff…

補碼詳細分析

補碼引入 舉一個生活化的例子 假設由一個掛鐘&#xff0c;它只能順時鐘調時間&#xff0c;那么它調時間就分成了一下兩種情況 正好順時針調就能調好 如&#xff1a;時針從5調到9需要逆時針調才能調好 如&#xff1a;時針從10調到7 在上面的情況中1是不用處理的&#xff0c;2…