对抽象工厂模式的理解

目录

  • 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.mzph.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…