對抽象工廠模式的理解

目錄

  • 1 背景
    • 1.1 題目描述
    • 1.2 輸入描述
    • 1.3 輸出描述
    • 1.4 輸入示例
    • 1.5 輸出示例
  • 2 抽象工廠模式
  • 3 思考
    • 3.1 我的實現
    • 3.2 什么時候用抽象工廠模式?(怎么用才是合適的?)
    • 3.3 [更好的例子](https://refactoringguru.cn/design-patterns/abstract-factory/java/example)
      • 3.3.1 背景
      • 3.3.2 示例

1 背景

題目來源:【設計模式專題之抽象工廠模式】3. 家具工廠

1.1 題目描述

小明家新開了兩個工廠用來生產家具,一個生產現代風格的沙發和椅子,一個生產古典風格的沙發和椅子,現在工廠收到了一筆訂單,請你幫他設計一個系統,描述訂單需要生產家具的信息。

1.2 輸入描述

輸入的第一行是一個整數 N(1 ≤ N ≤ 100),表示訂單的數量。
接下來的 N 行,每行輸入一個字符串,字符串表示家具的類型。家具類型分為 “modern” 和 “classical” 兩種。

1.3 輸出描述

對于每筆訂單,輸出字符串表示該訂單需要生產家具的信息。
modern訂單會輸出下面兩行字符串
modern chair
modern sofa
classical訂單會輸出下面兩行字符串
classical chair
classical soft

1.4 輸入示例

3
modern
classical
modern

1.5 輸出示例

modern chair
modern sofa
classical chair
classical sofa
modern chair
modern sofa

2 抽象工廠模式

  • 代碼示例:【來源】
import java.util.Scanner;// 抽象椅子接口
interface Chair {void showInfo();
}// 具體現代風格椅子
class ModernChair implements Chair {@Overridepublic void showInfo() {System.out.println("modern chair");}
}// 具體古典風格椅子
class ClassicalChair implements Chair {@Overridepublic void showInfo() {System.out.println("classical chair");}
}// 抽象沙發接口
interface Sofa {void displayInfo();
}// 具體現代風格沙發
class ModernSofa implements Sofa {@Overridepublic void displayInfo() {System.out.println("modern sofa");}
}// 具體古典風格沙發
class ClassicalSofa implements Sofa {@Overridepublic void displayInfo() {System.out.println("classical sofa");}
}// 抽象家居工廠接口
interface FurnitureFactory {Chair createChair();Sofa createSofa();
}// 具體現代風格家居工廠
class ModernFurnitureFactory implements FurnitureFactory {@Overridepublic Chair createChair() {return new ModernChair();}@Overridepublic Sofa createSofa() {return new ModernSofa();}
}// 具體古典風格家居工廠
class ClassicalFurnitureFactory implements FurnitureFactory {@Overridepublic Chair createChair() {return new ClassicalChair();}@Overridepublic Sofa createSofa() {return new ClassicalSofa();}
}public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 讀取訂單數量int N = scanner.nextInt();// 處理每個訂單for (int i = 0; i < N; i++) {// 讀取家具類型String furnitureType = scanner.next();// 創建相應風格的家居裝飾品工廠FurnitureFactory factory = null;if (furnitureType.equals("modern")) {factory = new ModernFurnitureFactory();} else if (furnitureType.equals("classical")) {factory = new ClassicalFurnitureFactory();}// 根據工廠生產椅子和沙發Chair chair = factory.createChair();Sofa sofa = factory.createSofa();// 輸出家具信息chair.showInfo();sofa.displayInfo();}}
}

3 思考

  • 這真的是抽象工廠模式嗎?太不靈活了。
  • 在上面的背景下,新增風格,新增家具,是很常見的需求。而按照上面的寫法,需要改動很多代碼才能實現。這不就完全沒體現抽象工廠模式的優勢了?

3.1 我的實現

public class Main {public static void main(String[] args) {FurnitureFactorySystem furnitureFactorySystem = FurnitureFactorySystem.getSingleton();Scanner scanner = new Scanner(System.in);int n = Integer.parseInt(scanner.nextLine());for (int i = 0; i < n; i ++) {String type = scanner.nextLine();furnitureFactorySystem.produce(type);}scanner.close();}
}/*** 生產限制:根據風格,成套出售。(對應現實生活,手機配色,對應整部手機)*/
class FurnitureFactorySystem {private static final Map<StyleEnum, FurnitureFactory> furnitureFactoryMap = new HashMap<>();private static FurnitureFactorySystem instance;private FurnitureFactorySystem() {furnitureFactoryMap.put(StyleEnum.MODERN, new ModernFurnitureFactory());furnitureFactoryMap.put(StyleEnum.CLASSIC, new ClassicFurnitureFactory());}public static FurnitureFactorySystem getSingleton() {if (instance == null) {synchronized (FurnitureFactorySystem.class) {if (instance == null) {instance = new FurnitureFactorySystem();}}}return instance;}public void produce(String type) {FurnitureFactory furnitureFactory = furnitureFactoryMap.get(StyleEnum.of(type));final List<Furniture> furnitures = Arrays.asList(new Chair(), new Sofa());furnitureFactory.createFurniture(furnitures);}
}interface FurnitureFactory {void createFurniture(List<Furniture> furnitures);
}class ModernFurnitureFactory implements FurnitureFactory {@Overridepublic void createFurniture(List<Furniture> furnitures) {for (Furniture furniture : furnitures) {furniture.create(StyleEnum.MODERN.getValue());}}
}class ClassicFurnitureFactory implements FurnitureFactory {@Overridepublic void createFurniture(List<Furniture> furnitures) {for (Furniture furniture : furnitures) {furniture.create(StyleEnum.CLASSIC.getValue());}}
}interface Furniture {void create(String type);
}class Chair implements Furniture {@Overridepublic void create(String type) {System.out.println(type + " " + FurnitureEnum.CHAIR.getValue());}
}class Sofa implements Furniture {@Overridepublic void create(String type) {System.out.println(type + " " + FurnitureEnum.SOFA.getValue());}
}@AllArgsConstructor
@Getter
enum StyleEnum {MODERN("modern"), CLASSIC("classical");private final String value;public static StyleEnum of(String value) {for (StyleEnum styleEnum : StyleEnum.values()) {if (styleEnum.getValue().equals(value)) {return styleEnum;}}// 如果沒有找到匹配的枚舉對象,可以拋出一個異常或返回nullthrow new IllegalArgumentException("Unknown StyleEnum: " + value);}
}/*** 家具*/
@AllArgsConstructor
@Getter
enum FurnitureEnum {CHAIR("chair"), SOFA("sofa");private final String value;public static FurnitureEnum of(String value) {for (FurnitureEnum furnitureEnum : FurnitureEnum.values()) {if (furnitureEnum.getValue().equals(value)) {return furnitureEnum;}}// 如果沒有找到匹配的枚舉對象,可以拋出一個異常或返回nullthrow new IllegalArgumentException("Unknown FurnitureEnum: " + value);}
}
  • 假設要新增風格和新家具,需要改動的代碼:
// 新增語句
private FurnitureFactorySystem() {furnitureFactoryMap.put(StyleEnum.MODERN, new ModernFurnitureFactory());furnitureFactoryMap.put(StyleEnum.CLASSIC, new ClassicFurnitureFactory());furnitureFactoryMap.put(StyleEnum.xxx, new xxxFurnitureFactory());
}public void produce(String type) {FurnitureFactory furnitureFactory = furnitureFactoryMap.get(StyleEnum.of(type));final List<Furniture> furnitures = Arrays.asList(new Chair(), new Sofa(), yyy); // 新增家具 furnitureFactory.createFurniture(furnitures);
}// 新增類
class xxxFurnitureFactory implements FurnitureFactory {@Overridepublic void createFurniture(List<Furniture> furnitures) {for (Furniture furniture : furnitures) {furniture.create(StyleEnum.xxx.getValue());}}
}// 新增類
class yyy implements Furniture {@Overridepublic void create(String type) {System.out.println(type + " " + FurnitureEnum.yyy.getValue());}
}// 新增枚舉
enum StyleEnum {MODERN("modern"), CLASSIC("classical"), xxx;
}// 新增枚舉
enum FurnitureEnum {CHAIR("chair"), SOFA("sofa"), yyy;
}

3.2 什么時候用抽象工廠模式?(怎么用才是合適的?)

  • 抽象工廠在實際的項目中相對也不常用,了解即可。

結論源自《設計模式之美》。

  • “3.1 我的實現”看似更靈活,但實際上不符合實際需要。
class Chair implements Furniture {@Overridepublic void create(String type) {System.out.println(type + " " + FurnitureEnum.CHAIR.getValue());}
}class Sofa implements Furniture {@Overridepublic void create(String type) {System.out.println(type + " " + FurnitureEnum.SOFA.getValue());}
}
  • 實際上,就是需要ModernChair、ModernSofa、ClassicalChair、ClassicalSofa這種對象。

3.3 更好的例子

3.3.1 背景

  • 按鈕和復選框,macos和windows,現實就存在4種對象:

    • macos按鈕、macos復選框
    • windows按鈕、windows復選框
  • 很顯然,代碼中就需要4個實體類與之對應。

  • 對于應用層,需要操作按鈕和復選框,前提是獲取對應的對象。而不同操作系統,返回的對象應該不同。

    • 此時,工廠不止生產一個對象,要同時能生產按鈕對象和復選框對象。由于工廠方法模式的特點是一個工廠就生產一個對象。因此,引入抽象工廠模式。

3.3.2 示例

public class Example {public static void main(String[] args) {GuiFactorySystem.paint("macos");GuiFactorySystem.paint("windows");}
}interface Button {void paint();
}class MacosButton implements Button {public void paint(){System.out.println("MacOS Button");}
}class WindowsButton implements Button {public void paint(){System.out.println("Windows Button");}
}interface Checkbox {void paint();
}class MacosCheckbox implements Checkbox {public void paint(){System.out.println("MacOS Checkbox");}
}class WindowsCheckbox implements Checkbox {public void paint(){System.out.println("Windows Checkbox");}
}// 抽象工廠
interface GuiFactory {Button createButton();Checkbox createCheckbox();
}class MacosGuiFactory implements GuiFactory {public Button createButton(){return new MacosButton();}public Checkbox createCheckbox(){return new MacosCheckbox();}
}class WindowsGuiFactory implements GuiFactory {public Button createButton(){return new WindowsButton();}public Checkbox createCheckbox(){return new WindowsCheckbox();}
}class GuiFactorySystem {private static final Map<String, GuiFactory> guiFactoryMap = new HashMap<>();static {guiFactoryMap.put("macos", new MacosGuiFactory());guiFactoryMap.put("windows", new WindowsGuiFactory());}private GuiFactorySystem() {}public static void paint(String type) {GuiFactory guiFactory = guiFactoryMap.get(type);Button button = guiFactory.createButton();Checkbox checkbox = guiFactory.createCheckbox();button.paint();checkbox.paint();}// 也可以單獨返回button對象,或者checkbox對象
}
  • 與工廠方法模式,最大的差別:
// 抽象工廠
interface GuiFactory {Button createButton();Checkbox createCheckbox();
}
  • 也不是不能用工廠方法模式實現,那就要4個工廠類(MacosButtonFactory, WindowsButtonFactory, MacosCheckboxFactory, WindowsCheckboxFactory)。而抽象工廠模式只用了2個工廠類(WindowsGuiFactory、MacosGuiFactory)。
  • 實際開發中,簡單工廠模式、工廠方法模式用的更多。

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

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

相關文章

【探索Linux】—— 強大的命令行工具 P.24(網絡基礎)

閱讀導航 引言一、計算機網絡背景1. 網絡發展歷史 二、認識 "協議"1. 網絡協議概念2. 網絡協議初識&#xff08;1&#xff09;協議分層&#xff08;2&#xff09;OSI參考模型&#xff08;Open Systems Interconnection Reference Model&#xff09;&#xff08;3&…

NoSQL--1.虛擬機網絡配置

目錄 1.初識NoSQL 1.1 NoSQL之虛擬機網絡配置 1.1.1 首先&#xff0c;導入預先配置好的NoSQL版本到VMware Workstation中 1.1.2 開啟虛擬機操作&#xff1a; 1.1.2.1 點擊開啟虛擬機&#xff1a; 1.1.2.2 默認選擇回車CentOS Linux&#xff08;3.10.0-1127.e17.x86_64) 7 …

cobalt strike釣魚lnk報錯:無法連接到遠程服務器

筆者在學習 cobalt strike 制作釣魚文件時發現多次失敗&#xff0c;在 win10 虛擬機的 powershell 的多次排查后發現這樣一個報錯&#xff1a; 使用“1”個參數調用“DownloadString”時發生異常:“無法連接到遠程服務器“ 經過多次排查后發現問題出在 cs 的 team server上&…

解決:Glide 在回調中再次加載圖片報錯

一、問題說明 Glide 加載圖片時監聽了回調&#xff0c;并在失敗時再次加載其它圖片后報錯。 代碼&#xff1a; Glide.with(mContext).load(imgTeacher).listener(new RequestListener<Drawable>() {Overridepublic boolean onLoadFailed(Nullable GlideException e, O…

MCU 串口接收環形緩沖區的實現

環形緩沖區 1. 環形緩沖區的特性 1.先進先出 2. 當緩沖區被使用完&#xff0c;且又有新的數據需要存儲時&#xff0c;丟掉歷史最久的數據&#xff0c;保存最新的數據 現實中的存儲介質都是線性的&#xff0c;因此我們需要做一下處理&#xff0c;才能在功能上實現環形緩沖區 …

[計算機網絡]--I/O多路轉接之poll和epoll

前言 作者&#xff1a;小蝸牛向前沖 名言&#xff1a;我可以接受失敗&#xff0c;但我不能接受放棄 如果覺的博主的文章還不錯的話&#xff0c;還請點贊&#xff0c;收藏&#xff0c;關注&#x1f440;支持博主。如果發現有問題的地方歡迎?大家在評論區指正 目錄 一、poll函…

web漏洞與規避

文章目錄 一、XSS 跨站腳本攻擊1.1 XSS攻擊的主要類型反射型XSS存儲型XSSDOM型XSS 1.2 前端開發如何應對XSS 二、CSRF 跨站請求偽造2.1 CSRF例子2.2 前端開發如何應對CSRF 三、SQL 注入3.1 前端如何防御SQL注入 四、前端如何使用CSP 一、XSS 跨站腳本攻擊 攻擊者通過在受害者的…

stm32學習筆記:IIC通信(未完)

概述 第一塊&#xff1a;介紹協議規則&#xff0c;然后用軟件模擬的形式來實現協議。 第二塊&#xff1a;介紹STM32的iic外設&#xff0c;然后用硬件來實現協議。 程序一現象&#xff1a;通過軟件I2C通信&#xff0c;對MPU6050芯片內部的寄存器進行讀寫&#xff0c;寫入到配…

【Synchronized同步原理】

Synchronized同步原理 1. synchronized的使用&#xff1f;2. 如何保證線程安全的&#xff1f;3.可重入原理&#xff08;加鎖次數計數器&#xff09;4. 原子性和可見性(順序性) 1. synchronized的使用&#xff1f; 對象鎖方法鎖類鎖 2. 如何保證線程安全的&#xff1f; publi…

關于數據提交上傳服務端的數據類型以及項目打包上線的流程

1 請求頭的類型&#xff1a; content-type&#xff1b; 01: application/json 數據以json格式請求&#xff1a;{"key":"value"} 02: application/x-www.form-urlencoded from表單的數據格式 name"zs"&age12 03 mutipart/form-data…

重學SpringBoot3-自動配置機制

重學SpringBoot3-自動配置機制 引言Spring Boot 自動配置原理示例&#xff1a;Spring Boot Web 自動配置深入理解總結相關閱讀 引言 Spring Boot 的自動配置是其最強大的特性之一&#xff0c;它允許開發者通過最少的配置實現應用程序的快速開發和部署。這一切都得益于 Spring …

飛槳(PaddlePaddle)模型保存與加載教程

文章目錄 飛槳&#xff08;PaddlePaddle&#xff09;模型保存與加載教程1. 概述2. 訓練調優場景2.1 保存動態圖模型2.2 加載動態圖模型 3. 推理部署場景3.1 使用基礎API 4. 其他場景4.1 舊版本格式兼容載入4.2 靜態圖模型的保存與加載 5. 總結 飛槳&#xff08;PaddlePaddle&am…

OmniPlan Pro mac版:簡單、智能,項目管理新選擇!

OmniPlan Pro是一款功能強大的項目管理軟件&#xff0c;它以其直觀的用戶界面和豐富的功能&#xff0c;幫助用戶輕松管理各種復雜的項目。無論是個人任務還是團隊協作&#xff0c;OmniPlan Pro都能提供全面的解決方案&#xff0c;讓項目管理變得更加簡單高效。 OmniPlan Pro軟…

從0開始回顧Mysql --- MySQL初體驗

大白話從0開始回顧MySQL&#xff0c;去除了一些繁瑣的操作的演示以及內容&#xff0c;如MySQL安裝等&#xff0c;本篇文章適合復習MySQL語法&#xff0c;學習MySQL語句&#xff0c;對MySQL不太熟練的同學&#xff0c;希望對大家有一些幫助。 MySQL初體驗 首先&#xff0c;我將…

如何在Window系統部署VisualSVN服務并結合cpolar實現無公網ip遠程訪問

文章目錄 前言1. VisualSVN安裝與配置2. VisualSVN Server管理界面配置3. 安裝cpolar內網穿透3.1 注冊賬號3.2 下載cpolar客戶端3.3 登錄cpolar web ui管理界面3.4 創建公網地址 4. 固定公網地址訪問 前言 SVN 是 subversion 的縮寫&#xff0c;是一個開放源代碼的版本控制系統…

數字孿生與智慧交通的融合發展:推動交通行業數字化轉型,構建智慧城市新生態

隨著信息技術的快速發展和城市化進程的深入推進&#xff0c;交通行業正面臨著前所未有的機遇與挑戰。傳統的交通管理模式已難以滿足日益增長的交通需求&#xff0c;而數字化轉型則成為了推動交通行業創新發展的必由之路。數字孿生技術作為一種前沿的信息技術手段&#xff0c;為…

聊一聊腦機接口

截至我所知的信息&#xff0c;腦機接口&#xff08;Brain-Computer Interface, BCI&#xff09;技術正在迅速發展&#xff0c;但仍處于相對早期階段。這一領域的研究涉及神經科學、工程學、計算機科學和人工智能等多個學科。以下是一些關于腦機接口目前進展的要點&#xff1a; …

基于springboot+vue的公寓報修管理系統

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

每天的三哥牌小雞腿沒了

查看印度基金(164824)公告&#xff0c;從2024年2月28日起&#xff0c;暫停印度基金的申購&#xff0c;限額100塊的一拖七套利告一段落。這意味著看好印度股市的國內投資者&#xff0c;以后只能通過在場內買入獲得份額。 關于暫停申購的原因&#xff0c;官方說是為保護基金持有…

學Python如此簡單--停車管理模塊

簡介 &#xff08;本停車場一個小時4塊&#xff09; 模塊名稱&#xff1a;黑心停車管理模塊 模塊功能&#xff1a;汽車進場錄入、汽車出場收費 代碼 #進入停車場 def enter():print(歡迎進入黑心停車場)#模擬識別車牌號car_number input(請輸入車牌號:)t 0 #停車時間car…