设计模式10-抽象工厂

抽象工厂 Abstract Factory

  • 动机
    • 原理
  • 结构
  • 优点
  • 代码推导
      • 不使用抽象工厂模式
      • 使用抽象工厂模式
      • 对比分析
        • 不使用抽象工厂模式的缺点
        • 使用抽象工厂模式的优点

抽象工厂(Abstract Factory)设计模式是一种创建型模式,它提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体类。这个模式的核心思想是将对象的创建和使用分离开来,以便在不修改客户端代码的情况下,能够方便地扩展系统的对象创建。

动机

在软件系统中,经常面临一系列相互依赖的对象的创建工作,同时由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化如何绕过常规的对象创建方法(new)提供一种封装机制来避免客户程序和这种多系列具体对象创建工作的紧耦合。

在软件开发中,常常会遇到需要创建一系列相关的对象的情况。例如,在一个图形用户界面(GUI)库中,可能需要同时创建按钮、复选框、文本框等不同的控件,而这些控件在不同的操作系统或主题下会有不同的实现。传统的工厂模式只能处理单一产品的创建,而无法处理一组相关产品的创建。在这种情况下,抽象工厂模式应运而生,它提供了一个解决方案来创建一系列相关对象,而无需关心具体的实现细节。

原理

抽象工厂模式的主要原理是定义一个用于创建一系列相关对象的接口(抽象工厂),而具体的工厂实现(具体工厂)则负责创建这些对象的具体实例。客户端代码只依赖于抽象工厂接口,而不依赖于具体工厂和具体产品,从而实现了对象创建的解耦。

结构

抽象工厂(AbstractFactory):定义了创建一系列相关产品的方法。通常是一个接口或抽象类。
具体工厂(ConcreteFactory):实现了抽象工厂接口,具体创建产品的实例。
抽象产品(AbstractProduct):定义了产品的接口或抽象类。
具体产品(ConcreteProduct):实现了抽象产品接口的具体类。
客户端(Client):通过抽象工厂接口来调用具体工厂创建产品,而不需要直接接触具体产品的实现。

优点

解耦产品和客户端:客户端不依赖于具体的产品类,而只依赖于抽象工厂,这样可以方便地更换具体工厂实现而不修改客户端代码。
易于扩展:添加新的产品族(即新的具体工厂)时,只需要实现新的具体工厂和相关的具体产品,而不需要修改现有的客户端代码。
统一的接口:所有产品通过抽象工厂提供的统一接口进行创建,方便管理和维护。

代码推导

为了更好地理解使用抽象工厂模式的好处,可以通过一个简单的例子进行代码推导。我们将展示不使用抽象工厂模式的代码,然后对比使用抽象工厂模式的代码,来说明其优点。

不使用抽象工厂模式

假设我们有一个应用程序,它需要根据不同的操作系统创建不同的UI组件(如按钮和文本框)。

// 抽象产品
interface Button {void render();
}interface TextBox {void render();
}// 具体产品
class WindowsButton implements Button {public void render() {System.out.println("Render Windows Button");}
}class WindowsTextBox implements TextBox {public void render() {System.out.println("Render Windows TextBox");}
}class MacOSButton implements Button {public void render() {System.out.println("Render MacOS Button");}
}class MacOSTextBox implements TextBox {public void render() {System.out.println("Render MacOS TextBox");}
}// 客户端代码
public class Application {private Button button;private TextBox textBox;public Application(String osType) {if (osType.equals("Windows")) {button = new WindowsButton();textBox = new WindowsTextBox();} else if (osType.equals("MacOS")) {button = new MacOSButton();textBox = new MacOSTextBox();}}public void renderUI() {button.render();textBox.render();}public static void main(String[] args) {Application app = new Application("Windows");app.renderUI();}
}

使用抽象工厂模式

下面是使用抽象工厂模式重构后的代码:

// 抽象产品
interface Button {void render();
}interface TextBox {void render();
}// 具体产品
class WindowsButton implements Button {public void render() {System.out.println("Render Windows Button");}
}class WindowsTextBox implements TextBox {public void render() {System.out.println("Render Windows TextBox");}
}class MacOSButton implements Button {public void render() {System.out.println("Render MacOS Button");}
}class MacOSTextBox implements TextBox {public void render() {System.out.println("Render MacOS TextBox");}
}// 抽象工厂
interface GUIFactory {Button createButton();TextBox createTextBox();
}// 具体工厂
class WindowsFactory implements GUIFactory {public Button createButton() {return new WindowsButton();}public TextBox createTextBox() {return new WindowsTextBox();}
}class MacOSFactory implements GUIFactory {public Button createButton() {return new MacOSButton();}public TextBox createTextBox() {return new MacOSTextBox();}
}// 客户端
class Application {private Button button;private TextBox textBox;public Application(GUIFactory factory) {button = factory.createButton();textBox = factory.createTextBox();}public void renderUI() {button.render();textBox.render();}public static void main(String[] args) {GUIFactory factory = new WindowsFactory();Application app = new Application(factory);app.renderUI();}
}

对比分析

不使用抽象工厂模式的缺点
  1. 紧耦合:客户端代码(Application 类)直接依赖于具体的产品类(WindowsButton, WindowsTextBox, MacOSButton, MacOSTextBox),这使得代码难以维护和扩展。
  2. 缺乏灵活性:如果要增加新的操作系统或新的产品族,需要修改客户端代码,这违背了开闭原则(对扩展开放,对修改关闭)。
  3. 代码冗长:每次添加新产品都需要在客户端代码中添加相应的逻辑,导致代码冗长且难以阅读。
使用抽象工厂模式的优点
  1. 解耦合:客户端代码只依赖于抽象工厂接口(GUIFactory)和抽象产品接口(Button, TextBox),与具体的产品类无关。这大大降低了代码的耦合度。
  2. 灵活性:添加新的产品族(如新的操作系统支持)只需实现新的具体工厂和具体产品,而不需要修改现有的客户端代码。
  3. 遵循开闭原则:系统可以方便地扩展新的功能(如新的产品族),而不需要修改现有的代码。
  4. 统一接口:通过抽象工厂提供的统一接口创建对象,代码更加简洁和一致。

通过这个例子,可以看出使用抽象工厂模式可以显著提高代码的灵活性、可维护性和扩展性,是一种非常有效的设计模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/47225.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch面部表情识别项目实战

新书速览|PyTorch深度学习与企业级项目实战-CSDN博客 本书案例比较丰富、比较完整,可以用于课题研究、毕业论文素材,值得大家收藏。 人脸表情是人类信息交流的重要方式,它所包含的人体行为信息与人的情感状态、精神状态、健康状态等有着极为…

Docker自建私有仓库遇到https问题

记录一下自己在自建Docker仓库的时候遇到的一个报错 问题 docker push registry:5000/library/centos:7 The push refers to repository [registry:5000/library/centos] Get "https://registry:5000/v2/": http: server gave HTTP response to HTTPS client解决办…

关于Ubuntu22.04中的Command ‘vim‘ not found, but can be installed with:

前言 在Ubuntu终端编辑文本内容时需要利用vim,但新安装的虚拟机中并未配置vim,本文记录了vim的安装过程。 打开终端后,在home目录中输入 vim test.txt但提示报错,提示我们没有找到vim,需要通过以下命令进行安装&…

yearrecord——一个类似痕迹墙的React数据展示组件

介绍一下自己做的一个类似于力扣个人主页提交记录和GitHub主页贡献记录的React组件。 下图分别是力扣个人主页提交记录和GitHub个人主页的贡献记录,像这样类似痕迹墙的形式可以比较直观且高效得展示一段时间内得数据记录。 然而要从0实现这个功能还是有一些麻烦得…

vue搜索框过滤--- computed、watch区别

vue组件选项(component options) 1. computed(计算属性) 用途:computed属性用于声明性地描述一些依赖其它响应式属性的数据。当依赖的响应式属性变化时,计算属性会自动重新求值。缓存:计算属性…

等保-Linux等保测评

等保-Linux等保测评 1.查看相应文件,账户xiaoming的密码设定多久过期 rootdengbap:~# chage -l xiaoming Last password change : password must be changed Password expires : pass…

数据库管理-第221期 Oracle的高可用-04(20240717)

数据库管理221期 2024-07-17 数据库管理-第221期 Oracle的高可用-04(20240717)1 ADG2 连接配置2.1 TNS2.2 JDBC2.3 JAVA连接池2.3.1 Oracle UCP2.3.2 应用连接池基础配置 总结 数据库管理-第221期 Oracle的高可用-04(20240717) 作…

mysql5.7版本字符集编码

默认character_set_databaselatin1 当你字段插入中文值的时候,会报错。 所以修改为了character_set_databaseutf8既可以。 character_set_server他的范围更大,属于服务器级别。

自然语言处理NLP--文本相似度面试题

自然语言处理NLP--文本相似度面试题 问题 1: 什么是文本相似度,如何在搜索系统中应用?问题 2: 如何使用TF-IDF进行文本相似度计算?问题 3: 使用Word2Vec进行文本相似度计算的过程是怎样的?问题 4: BERT如何用于文本相似度计算&…

LeetCode 852, 20, 51

目录 852. 山脉数组的峰顶索引题目链接标签二分思路代码 三分思路代码 20. 有效的括号题目链接标签思路代码 51. N 皇后题目链接标签思路回溯如何保证皇后之间无法互相攻击 代码 852. 山脉数组的峰顶索引 题目链接 852. 山脉数组的峰顶索引 标签 数组 二分查找 二分 思路…

网络安全-网络安全及其防护措施6

26. 访问控制列表(ACL) ACL的定义和作用 访问控制列表(ACL)是一种网络安全机制,用于控制网络设备上的数据包流量。通过ACL,可以定义允许或拒绝的流量,增强网络的安全性和管理效率。ACL通过在路…

逍遥模拟器安装Magisk和EDXPosed教程

资源下载: 逍遥模拟器安装Magisk和EDXPosed教程 - 多开鸭资源下载: MagiskEDXP教程文件 单独的逍遥模拟器使用的版本EDXPosed打包下载(下载之后解压出来一共4个文件): 如果要按本教程安装就务必使用这里的安装包&…

翁恺-C语言程序设计-10-0. 说反话

10-0. 说反话 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。 输入格式:测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母&#…

爬虫(一)——爬取快手无水印视频

前言 最近对爬虫比较感兴趣,于是浅浅学习了一些关于爬虫的知识。爬虫可以实现很多功能,非常有意思,在这里也分享给大家。由于爬虫能实现的功能太多,而且具体的实现方式也有所不同,所以这里开辟了一个新的系列——爬虫…

记录贴-芋道源码-环境搭建

文字讲解 链接: 芋道源码-环境搭建(一)后端 链接: 芋道源码-环境搭建(二)前端 链接: 基于FastGPT和芋道源码挑战一句话生成代码 视频讲解 链接: 芋道源码零基础启动教程(上) 链接: 芋道源码零基础启动教程…

bs4取值技巧的详细介绍

1. 基本取值方法&#xff1a; find()&#xff1a; 查找第一个匹配的标签。soup.find(h1) # 查找第一个<h1>标签find_all()&#xff1a; 查找所有匹配的标签。soup.find_all(a) # 查找所有<a>标签select()&#xff1a; 使用CSS选择器查找标签。soup.select(.item…

进阶篇:如何使用 Stable Diffusion 优化神经网络训练

进阶篇&#xff1a;如何使用 Stable Diffusion 优化神经网络训练 一、引言 随着深度学习的发展&#xff0c;神经网络模型在各个领域取得了显著的成果。然而&#xff0c;在训练复杂神经网络时&#xff0c;模型的稳定性和优化问题始终是一个挑战。Stable Diffusion&#xff08;…

用AI生成Springboot单元测试代码太香了

你好&#xff0c;我是柳岸花开。 在当今软件开发过程中&#xff0c;单元测试已经成为保证代码质量的重要环节。然而&#xff0c;编写单元测试代码却常常让开发者头疼。幸运的是&#xff0c;随着AI技术的发展&#xff0c;我们可以利用AI工具来自动生成单元测试代码&#xff0c;极…

基于单片机的停车场车位管理系统设计

1.简介 停车场车位管理系统是日常中随处可见的一种智能化车位管理技术&#xff0c;使用该技术可以提高车位管理效率&#xff0c;从而减轻人员车位管理工作负荷。本系统集成车牌识别、自动放行、自助缴费等技术&#xff0c;并且具备车位占用状态实时监测与车位数量实时统计、查询…

SQL进阶--条件分支

一、问题引入 在SQL中&#xff0c;虽然不像某些编程语言&#xff08;如C、Java或Python&#xff09;那样直接支持if-else这样的条件分支语句&#xff0c;但它提供了几种方式来实现条件逻辑&#xff0c;这些方式主要通过CASE语句、IF()函数&#xff08;在某些数据库如MySQL中&a…