抽象工厂模式(Abstract Factory)
抽象工厂模式提供一个创建一组相关或相互依赖的对象的接口,而无须指定它们具体的类,每个子类可以生产一系列相关的产品。
The Abstract Factory Pattern is to provide an interface for creating families of related or dependent objects
without specifying their concrete classes.
结构设计
抽象工厂模式包含如下角色:
AbstractFactory,抽象工厂,负责声明一组产品创建的工厂方法,每个方法返回一个AbstractProduct类型的对象。
ConcreteFactory,具体工厂,用来实现AbstractFactory声明的工厂方法,以创建具有特定实现的产品对象。
AbstractProduct,抽象产品,用来声明一组不同但相关的产品声明的接口。
ConcreteProduct,具体产品,用来实现AbstractProduct的接口,以定义特定的产品。
抽象工厂模式类图表示如下:
伪代码实现
接下来将使用代码介绍下抽象工厂模式的实现。
(1) 定义一组产品(ProductA、ProductB、…)抽象类(也可以是基类),对产品接口进行声明。然后定义具体产品(Concrete Products),实现产品声明的接口。
public abstract class ProductA {abstract void function();
}
public class ConcreteProductA1 extends ProductA {@Overridepublic void function() {System.out.println("---------do some thing in a ConcreteProductA1 instance---------");}
}
public class ConcreteProductA2 extends ProductA {@Overridepublic void function() {System.out.println("---------do some thing in a ConcreteProductA2 instance---------");}
}public abstract class ProductB {abstract void foo();
}
public class ConcreteProductB1 extends ProductB {@Overridepublic void foo() {System.out.println("---------do some thing in a ConcreteProductB1 instance---------");}
}
public class ConcreteProductB2 extends ProductB {@Overridepublic void foo() {System.out.println("---------do some thing in a ConcreteProductB2 instance---------");}
}
(2) 定义产品工厂(Product Factory)抽象类或基类,声明返回一组产品对象的工厂方法。每个方法的返回对象类型必须与产品接口相匹配。然后定义具体产品工厂(Concrete Product Factories)重写基础工厂方法, 使其返回不同类型的产品。
public abstract class ProductFactory {/*** 生产产品A*/abstract ProductA createProductA();/*** 生产产品B*/abstract ProductB createProductB();
}public class ProductFactory1 extends ProductFactory {@Overridepublic ProductA createProductA() {System.out.println("create ProductA");return new ConcreteProductA1();}@Overridepublic ProductB createProductB() {System.out.println("create ProductB");return new ConcreteProductB1();}
}public class ProductFactory2 extends ProductFactory {@Overridepublic ProductA createProductA() {System.out.println("create ProductB");return new ConcreteProductA2();}@Overridepublic ProductB createProductB() {System.out.println("create ProductB");return new ConcreteProductB2();}
}
(3) 客户端调用。支持多种调用方式,如:直接在方法中实例化工厂子类、提供静态方法,支持方法参数中传递工厂对象、提供对象方法,使用构造函数中传入的工厂对象。
public class AbstractFactoryClient {private ProductFactory factory;public AbstractFactoryClient(ProductFactory factory) {this.factory = factory;}// 调用方式一:方法中实例化工厂子类public void test() {// (1) 实例化产品工厂ProductFactory productFactory1 = new ProductFactory1();// (2) 生产产品ProductA productA1 = productFactory1.createProductA();// (3) 使用产品productA1.function();// 下同ProductB productB1 = productFactory1.createProductB();productB1.foo();ProductFactory productFactory2 = new ProductFactory2();ProductA productA2 = productFactory2.createProductA();productA2.function();ProductB productB2 = productFactory2.createProductB();productB2.foo();}// 调用方式二:工厂对象作为方法参数(工具类方法)public static void foo(ProductFactory factory) {ProductA productA1 = factory.createProductA();productA1.function();ProductB productB1 = factory.createProductB();productB1.foo();}// 调用方式三:使用构造函数中传入的工厂(工厂一旦绑定,无法修改)public void foo() {ProductA productA1 = this.factory.createProductA();productA1.function();ProductB productB1 = this.factory.createProductB();productB1.foo();}
}
适用场景
在以下情况下可以考虑使用抽象工厂模式:
(1) 如果需要与多个不同系列的相关产品交互,但无法预知对象确切类别及其依赖关系时,可使用抽象工厂。
抽象工厂将创建产品的代码与实际使用产品的代码分离,从而能在不影响其他代码的情况下扩展产品创建部分代码。
(2) 如果希望用户能扩展软件库或框架的内部组件,可使用抽象工厂。
继承是扩展软件库或框架默认行为的最简单方法。但是,当使用子类替代标准组件时,框架如何辨识出该子类?解决方案是将各框架中构造组件的代码集中到单个工厂方法中,并在继承该组件之外允许任何人对该方法进行重写。
(3) 如果存在一个基于一组抽象方法的类,且其主要功能因此变得不明确,可使用抽象工厂。
在设计良好的程序中, 每个类仅负责一件事。如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。
优缺点
抽象工厂模式有以下优点:
(1) 将创建产品的代码与实际使用产品的代码分离(解耦),避免产品创建工厂和实际产品之间的紧耦合。
(2) 单一职责原则。产品创建代码放在单独的类里,从而使得代码更容易维护。
(3)开闭原则。无需更改客户端调用代码, 就可以在程序中引入新的产品类型。
但是抽象工厂模式也存在以下缺点:
(1) 应用抽象工厂模式需要引入许多新的子类,代码会因此变得更复杂。最好的情况是将该模式引入产品类的现有层次结构中(将工厂类组合到产品类里)。
(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到反射等技术,增加了系统的实现难度。
参考
https://www.edrawsoft.cn/ 亿图图示
《设计模式:可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著 李英军, 马晓星 等译
https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/abstract_factory.html 抽象工厂模式
https://refactoringguru.cn/design-patterns/abstract-factory 抽象工厂模式
https://blog.csdn.net/ShuSheng0007/article/details/86644481 秒懂设计模式之抽象工厂模式
https://www.cnblogs.com/adamjwh/p/9033552.html 简说设计模式——抽象工厂模式
相关文章:

抽象工厂模式(Abstract Factory)
抽象工厂模式提供一个创建一组相关或相互依赖的对象的接口,而无须指定它们具体的类,每个子类可以生产一系列相关的产品。 The Abstract Factory Pattern is to provide an interface for creating families of related or dependent objects without s…...
Java 实现下载文件工具类
package com.liunian.utils;import lombok.SneakyThrows;import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream;/*** ClassName DownloadFileUtils* Author liuyan 下载文件工具类…...
C# 12 预览版的新功能
作者:Kathleen Dollard 排版:Alan Wang Visual Studio 17.7 Preview 3 和 .NET 8 Preview 6 的发布推进了 C# 12的发展。此预览版包含的功能为将来的性能增强奠定了基础。现在,您能够在库中更方便的使用内联函数。此预览版首次推出了一项实验…...

34.利用matlab解 多变量多目标规划问题(matlab程序)
1.简述 学习目标:适合解 多变量多目标规划问题,例如 收益最大,风险最小 主要目标法,线性加权法,权值我们可以自己设定。 收益函数是 70*x(1)66*x(2) ; 风险函数是 0.02*x(1)^20.01*x(2)^20.04*(x…...
暑假刷题第18天--7/30
165. 小猫爬山 - AcWing题库(dfs) #include<iostream> #include<string> #include<bitset> #include<cstring> #include<algorithm> using namespace std; const int N18; bool vis[N]; int a[N],n,ans,sum[N],k; bool cmp(int x,int y){retur…...

通向架构师的道路之Apache整合Tomcat
一、先从J2EE工程的通用架构说起 这是一个通用的Web即B/S工程的架构,它由: Web Server App Server DB Server 三大部分组成,其中: Web Server 置于企业防火墙外,这个防火墙,大家可以认为是…...

如何消除“信息孤岛”对业务增长的威胁?
根据CMSWire的数据,员工平均每天要花36%的时间来查找和整合信息。但44%的情况下,他们找不到信息。这种时间和精力的浪费就是信息孤岛造成的。 什么是信息孤岛? 当部门存储数据并限制其他人访问数据时,就会出现信息孤岛ÿ…...

Kali部署dvwa和pikachu靶场
kali换源 进入 vim /etc/apt/sources.list deb https://mirrors.aliyun.com/kali kali-rolling main non-free contrib deb-src https://mirrors.aliyun.com/kali kali-rolling main non-free contrib替换完后更新源 apt-get upadteDVWA靶场环境搭建 使用git从github上把DV…...
LeetCode解法汇总722. 删除注释
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给一个 C 程序,删除程序中的注释。这个程序source是一个数组&#x…...

Linux中的firewall-cmd
2023年8月4日,周五上午 目录 打开端口关闭端口查看某个端口是否打开查看当前防火墙设置firewall-cmd中的服务在防火墙中什么是服务?为什么会有服务?打开或关闭服务查看某个服务是否打开firewall-cmd中的 zones查看所有可用的zones࿰…...

python 最大归一化
最大归一化是将数据转化到[-1,1]范围之间。公式如下 其中|X|max为x特征的绝对值的最大值。 数据标准化算法介绍—数据建模工具_预处理_Max_字段 """ 最大绝对值归一化(max abs normalization ):也就是将数值变为单位长度&…...

Netty:ByteBuf写入数据、读出数据
介绍 Netty的ByteBuf数据位置索引是0开始的。 可以用ByteBuf的getByte(int index)方法从指定位置读出一字节,这个操作不会改变ByteBuf的readerIndex 或者 writerIndex 的位置。如果index小于0,或者index 1大于ByteBuf的容量,就会抛出IndexO…...
C++(15):面向对象程序设计
面向对象程序设计概述 面向对象程序设计(object-oriented programming)的核心思想是数据抽象、继承和动态绑定。 1.使用数据抽象,可以将类的接口与实现分离; 2.使用继承,可以定义相似的类型并对其相似关系建模&#x…...

2023牛客暑期多校训练营6-A Tree
2023牛客暑期多校训练营6-A Tree https://ac.nowcoder.com/acm/contest/57360/A 文章目录 2023牛客暑期多校训练营6-A Tree题意解题思路代码 题意 解题思路 最大价值和这个数据范围,一眼 d p dp dp。 直接在树上并不好处理,问题是如何有效转化、处理…...
Vc - Qt - QPainter::SmoothPixmapTransform及QPainter::Antialiasing
QPainter::SmoothPixmapTransform是一个标志,用于指定绘制操作中的平滑像素变换行为。当使用QPainter绘制一幅图像时,设置SmoothPixmapTransform标志可以使图像变换过程更加平滑,减少锯齿状边缘的出现。此标志通常用于绘制缩放后图像的情况。…...
【练习】条件变量:创建三个线程 id号为ABC,三个线程循环打印自己的ID号,运行顺序为 ABCABC
题目: 创建三个线程 id号为ABC,三个线程循环打印自己的ID号,运行顺序为 ABCABC......要求使用条件变量 #include <stdio.h> #include <pthread.h> #include <unistd.h>//创建互斥锁 pthread_mutex_t mutex PTHREAD_MUTE…...

SpringBoot项目修改中静态资源,只需刷新页面无需重启项目(附赠—热加载)
初衷 💢初衷💢 因为一遍遍修改并重启项目觉得很麻烦,所以刚开始就自己给项目配置了热加载,但奈何代码更新还是慢,还不如我重启一遍项目的速度,所以放弃了自己上网找到的热加载配置。直到我debugger前端代码…...
clear_data_code_2d_model
dev update off () dev close window () ImageFiles:-./二维条码/read_image(Image,ImageFiles 十二维条码原图.png)dev_open_window_fit_image(Image,0,0,-,-1,WindowHandle)set_display_font (WindowHan…...
“深入剖析JVM:揭秘Java虚拟机的工作原理“
标题:深入剖析JVM:揭秘Java虚拟机的工作原理 摘要:本文将深入探讨Java虚拟机(JVM)的工作原理,包括JVM的架构、内存管理、垃圾回收、即时编译等关键技术。通过对JVM的剖析,我们可以更好地理解Ja…...
elementui表格table中实现内容的换行
问题 elementui 中的 table 行内的内容不能进行换行。 解决方法 思路: 利用 作用域插槽 结合 v-html,通过作用域插槽传递内容到表格行内,再通过 v-html 进行内容的替换。 代码: <el-table:data"tableData"stri…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...