Java设计模式 | 抽象工厂模式

在这里插入图片描述

抽象工厂模式

工厂方法模式中考虑的是一类产品的生产,如幼儿园只培养小朋友,鞋厂只生产鞋子。
这些工厂只生产同种类产品,同种类产品称为同等级产品,即工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂都是综合型工厂,可以生产多等级(种类)的产品,如大学既有软件工程专业,也有汉语言文学专业等。
抽象工厂模式将考虑多等级产品的生产,将一个具体工厂所生产的位于不同等级的一系列产品称为一个产品族。如下图,横轴是产品等级,也就是一类产品,纵轴是产品族,表示同一品牌的产品,同一品牌的产品产自同一工厂。
image-20200401214509176.png

是什么

抽象工厂模式就是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无需指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。(抽象工厂模式可以确保一系列相关的产品被一起创建,这些产品能够相互配合使用)
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级(种类)的产品。

结构

抽象工厂的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品
  • 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建
  • 抽象产品(Abstract Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品
  • 具体产品(Concrete Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系
实现

咖啡店业务发生发生变化,不仅要生产咖啡,还要生产甜点,如提拉米苏、抹茶慕斯等。如果按照工厂方法模式,需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸的情况。其中拿铁咖啡、美式咖啡是一个产品等级,都是咖啡;提拉米苏和抹茶慕斯也是一个产品等级;拿铁咖啡和提拉米苏是同一产品族(都属于意大利风味);美式咖啡和抹茶慕斯是同一产品族(都是美式风味)。可以使用抽象工厂模式实现:
实现抽象⼯⼚模式,一般需要遵循以下步骤:

  • 定义抽象产品接⼝(可以有多个),接⼝中声明产品的公共⽅法。
  • 实现具体产品类,在类中实现抽象产品接⼝中的⽅法。
  • 定义抽象⼯⼚接⼝,声明⼀组⽤于创建产品的⽅法。
  • 实现具体⼯⼚类,分别实现抽象⼯⼚接⼝中的⽅法,每个⽅法负责创建⼀组相关的产品。
  • 在客户端中使⽤抽象⼯⼚和抽象产品,⽽不直接使⽤具体产品的类名。

image.png
抽象工厂:

public interface DessertFactory {// 生产咖啡的功能Coffee createCoffee();// 生产甜点的功能Dessert createDessert();
}

具体工厂(美式风味甜品工厂):

public class AmericanDessertFactory implements DessertFactory{@Overridepublic Coffee createCoffee() {return new AmericanCoffee();}@Overridepublic Dessert createDessert() {return new MatchaMousse();}
}

具体工厂(意大利式风味甜品工厂):

public class ItalyDessertFactory implements DessertFactory {@Overridepublic Coffee createCoffee() {return new LatteCoffee();}@Overridepublic Dessert createDessert() {return new Trimisu();}
}

抽象产品(咖啡类):

public abstract class Coffee {// 获取咖啡名public abstract String getName();// 加糖public void addSugar(){System.out.println("加糖");}// 加奶public void addMilk(){System.out.println("加奶");}
}

抽象产品(甜点类):

public abstract class Dessert {public abstract void show();
}

具体产品(美式咖啡类):

public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}
}

具体产品(拿铁咖啡类):

public class LatteCoffee extends Coffee {@Overridepublic String getName() {return "拿铁咖啡";}
}

具体产品(抹茶慕斯类):

public class MatchaMousse extends Dessert {@Overridepublic void show() {System.out.println("抹茶慕斯");}
}

具体产品(提拉米苏类):

public class Trimisu extends Dessert {@Overridepublic void show() {System.out.println("提拉米苏");}
}

测试:

public class Client {public static void main(String[] args) {// 创建意大利风味的甜品工厂对象
//        DessertFactory dessertFactory = new ItalyDessertFactory();// 创建美式风味的甜品工厂对象DessertFactory dessertFactory = new AmericanDessertFactory();// 生产对应的咖啡和甜点Coffee coffee = dessertFactory.createCoffee();Dessert dessert = dessertFactory.createDessert();System.out.println(coffee.getName());dessert.show();}
}

总结

抽象工厂模式能够保证一系列相关产品一起使用,且在不改变客户端代码的情况下,可以方便的替换整个产品系列。但是需要增加新产品类时,除了要增加新的具体产品类,还需要修改抽象⼯⼚接⼝及其所有的具体⼯⼚ 类,扩展性相对较差。
优点:

  • 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象
  • 方便替换整个产品系列

缺点:

  • 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改
使用场景
  • 当需要创建的对象是一系列相关联或相互依赖的产品族时
  • 系统中有多个产品族,但每次只使用其中的某一产品族
  • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构
简单工厂、工厂方法和抽象工厂的区别
  • 简单⼯⼚模式:⼀个⼯⼚⽅法创建所有具体产品
  • ⼯⼚⽅法模式:⼀个⼯⼚⽅法创建⼀个具体产品
  • 抽象⼯⼚模式:⼀个⼯⼚⽅法可以创建⼀类具体产品

模式扩展

简单工厂+配置文件解耦

可以通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合。在工厂类中加载配置文件中的全类名,并创建对象进行存储,客户端如果需要对象,直接进行获取即可
配置文件bean.properties:

american=com.jmd.factory.configfactory.AmericanCoffee
latte=com.jmd.factory.configfactory.LatteCoffee

工厂类:

public class CoffeeFactory {// 加载配置文件,获取配置文件中配置的全类名,并创建对象进行存储// 1 定义容器存储咖啡对象private static HashMap<String, Coffee> coffeeMap = new HashMap<>();// 2 加载配置文件,只需加载一次static {// 2.1 创建Properties对象Properties p = new Properties();// 2.2 加载配置文件load()InputStream rs = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");if (rs == null) {throw new RuntimeException("找不到配置文件");}try {p.load(rs);// 从p集合中获取全类名并创建对象for (Object key : p.keySet()) {// 2.3 获取全类名String className = p.getProperty((String) key);// 通过反射创建对象// 2.4 加载类Class clazz = Class.forName(className);// 2.5 创建对象Coffee coffee = (Coffee) clazz.newInstance();// 2.6 将对象存入容器coffeeMap.put((String) key, coffee);}} catch (Exception e) {e.printStackTrace();}}// 根据名称获取对象public static Coffee createCoffee(String type) {return coffeeMap.get(type);}
}

抽象产品(咖啡类):

public abstract class Coffee {// 获取咖啡名public abstract String getName();// 加糖public void addSugar(){System.out.println("加糖");}// 加奶public void addMilk(){System.out.println("加奶");}
}

具体产品(美式咖啡):

public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}
}

具体产品(拿铁咖啡):

public class LatteCoffee extends Coffee {@Overridepublic String getName() {return "拿铁咖啡";}
}

测试:

public class Client {public static void main(String[] args) {Coffee coffee = CoffeeFactory.createCoffee("latte");System.out.println(coffee.getName());System.out.println("===========================");Coffee coffee2 = CoffeeFactory.createCoffee("american");System.out.println(coffee2.getName());}
}

静态成员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件以及创建对象写在静态代码块中,目的就是只需要执行一次

JDK源码分析

  • Calendar类中的getInstance()方法使用的是简单工厂模式
  • 单列集合迭代器Collection.iterator()方法使用的是工厂方法模式
  • DateForamt类中的getInstance()方法使用的是简单工厂模式

github笔记

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

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

相关文章

【计算机网络】计算机网络概述

文章目录 一、计算机网络的概念二、 计算机网络的功能1. 数据通信2. 资源共享3. 分布式处理4. 提高可靠性5. 负载均衡 补充&#xff1a; 计算机的发展阶段小结三、计算机网络的组成1. 组成部分2. 工作方式3. 功能组成 四、 计算机网络的分类1. 按分布范围2. 按使用者3. 按交换技…

Docker 【通过Dockerfile构建镜像】【docker容器与镜像的关系】

文章目录 前言一、前期的准备工作二、上手构建一个简单的镜像三、DcokerFile1 指令总览2 指令详情 四、Dockerfile文件规范五、docker运行build时发生了什么?六、调试手段1. 修改镜像打包后&#xff0c;如何验证新内容已更新至镜像 七、Dockerfile优化方案 前言 docker构建镜…

JavaEE-文件操作和IO

我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进⾏数据保存时&#xff0c;往往不是保存成⼀个整体&#xff0c;⽽是独⽴成⼀个个的单位进⾏保存&#xff0c;这个独⽴的单位就被抽象成⽂件的概念&#xff0c;就类似办公桌上的⼀份份真…

stm32平衡车

目录 一.所需材料 二.PID算法&#xff08;简单说明&#xff09; 直立环 速度环 串级PID 三.使用到的外设 1.定时器输出比较-PWM 2.定时器编码器模式 3.编码器读取速度 4.电机驱动函数 5.外部中断 四、小车 调试 一.所需材料 1.陀螺仪MPU6050--读取三轴的加速度…

隐语笔记2 —— 隐私计算开源如何助力数据要素流通

数据生命周期 数据流转链路主要包括&#xff1a;采集、存储、加工、使用、提供、传输 数据要素外循环是构建数据要素市场的核心 数据外循环中的信任焦虑 三个代表性问题&#xff1a; 不可信内部人员不按约定使用用户隐私泄漏 数据权属问题 解决方案&#xff1a;从主体信任…

JDK下载配置

一、JDK的作用 Java开发环境&#xff1a;JDK提供了完整的Java开发环境&#xff0c;包含编译器&#xff08;javac&#xff09;、解释器&#xff08;java&#xff09;、打包工具&#xff08;jar&#xff09;、文档生成工具&#xff08;javadoc&#xff09;等一系列工具&#xff0…

SpringBoot健康监控

文章目录 1-SpringBoot2-监控-健康监控服务2-SpringBoot2-监控-Admin可视化 在Spring Boot中&#xff0c;可以通过Actuator模块实现应用程序的健康监控。Actuator是Spring Boot提供的一个用于监控和管理应用程序的模块&#xff0c;可以轻松地查看应用程序的运行状况、性能指标和…

有什么可以下载网页视频的浏览器插件 浏览器如何下载网页视频 网页视频怎么下载到本地 网页视频下载软件 IDM下载

在视频网站上看电影追剧&#xff0c;已经成为了大众生活中必不可少的一部分。为了保护自家视频的版权&#xff0c;很多平台都禁止用户下载会员视频。其实只要掌握了正确的方法&#xff0c;一样可以将会员视频下载到本地保存。那么有关有什么可以下载网页视频的浏览器&#xff0…

Websocket + Vue使用

这里有一篇文档可以参考一下> 闪现 POM文件 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.7.0</version> </dependency> WebSocketConf…

数据库之MongoDB应用与开发

MongoDB应用与开发 1. MongoDB安装 l 官网下载安装介质&#xff1a; Try MongoDB Atlas Products | MongoDB 选择对应版本 修改环境变量 vi /etc/profile export MONGODB_HOME/home/lijin/mongodb export PATH P A T H : PATH: PATH:MONGODB_HOME/bin source /etc/profile …

TnT-LLM: Text Mining at Scale with Large Language Models

TnT-LLM: Text Mining at Scale with Large Language Models 相关链接&#xff1a;arxiv 关键字&#xff1a;Large Language Models (LLMs)、Text Mining、Label Taxonomy、Text Classification、Prompt-based Interface 摘要 文本挖掘是将非结构化文本转换为结构化和有意义的…

矩阵计算-线性系统和 LU 分解

一、三角系统 …… 二、高斯消元法 …… 三、LU分解--直接三角分解法 求解线性方程Axb&#xff1a; 参考视频&#xff1a;【数值分析】矩阵LU三角分解| 速成讲解 考试宝典_哔哩哔哩_bilibili 令ALU&#xff0c;其中L是单位下三角矩阵&#xff08;对角线上元素都是1&#xff…

精神暴力的来源与解药

导致人生病的&#xff0c;不仅是病毒或细菌&#xff0c;也有精神暴力。与病毒破坏物理肌体、摧毁生命不同&#xff0c;精神暴力是让人们在过度的自我狂热中燃尽自我、而毁灭自身的。 21世纪以来&#xff0c;精神方面的疾病越来越多&#xff0c;为什么这样呢&#xff1f;大的背景…

git基础-查看提交历史

查看提交历史 在创建了多个提交之后&#xff0c;或者如果克隆了一个具有现有提交历史的存储库&#xff0c;可能会想要回顾一下发生了什么。最基本和强大的工具就是 git log 命令。 运行下git log查看下输出状态 默认情况下&#xff0c;不带任何参数运行 git log 命令会以逆时…

【工具】cassetteai — 制作音乐就像现在写提示一样简单

Cassette 是一种人工智能驱动的音乐创作工具,使各种技能水平的用户都可以根据自己的特定需求和偏好生成高质量、免版税的音乐曲目。它基于基于潜在扩散 (LDM) 的机器学习模型,可以使用用户提供的文本描述来想象节拍。它具有易于使用的界面,用户可以输入各种参数,例如所需的…

AGV|机器人导航识别二维码视觉传感器TDCS-0100与上位机PLC联机实例说明

目前二维码视觉导航的AGV出货量非常大&#xff0c;几乎都是仓储型AGV使用的导航方式。在地面或者天花板等位置标贴二维码作为标记点&#xff0c;通过扫描读取二维码信息和二维码相对相机的角度来确定当前位置。 本文重点介绍AGV|机器人导航识别二维码视觉传感器TDCS-0100与上位…

unity学习(68)——相机/模型的旋转/位置计算

这个比想象中要难&#xff0c;而且需要自己写。 1.相机可以转xy两个位置&#xff0c;可以点头和转圈。注意这里有一个if判断&#xff08;后面返回来发现了这些问题&#xff09; 2.角色不能点头&#xff0c;只能转圈。 难得是移动方向&#xff0c;因为移动方向(位置)和转向是相…

在Sequence中缓存Niagara粒子轨道

当Sequence中粒子特效较多时&#xff0c;播放检查起来较为麻烦&#xff0c;而使用Niagara缓存功能可将粒子特效方便的缓存起来&#xff0c;并且还可以更改播放速度与正反播放方向&#xff0c;便于修改。 1.使用Niagara缓存需要先在插件里打开NiagaraSimCaching 2.创建一个常…

web前端之行为验证码、不同设备和屏幕尺寸呈现不同大小、元素宽度根据视口宽度进行调整、元素或图片裁剪、图片验证码

MENU 前言版本一(htmlJScss)版本二(htmlJScsscanvas) 前言 1、版本一的样式比较齐全&#xff1b; 2、版本二的JS逻辑和功能效果比较完善&#xff0c;且是别人的代码&#xff0c;后续会对样式进行完善。[Gitee | 哔哩哔哩]&#xff1b; 3、两个版本各有千秋&#xff0c;主要学习…

CRC计算流程详解和FPGA实现

一、概念 CRC校验&#xff0c;中文翻译过来是&#xff1a;循环冗余校验&#xff0c;英文全称是&#xff1a;Cyclic Redundancy Check。是一种通过对数据产生固定位数的校验码&#xff0c;以检验数据是否存在错误的技术。 其主要特点是检错能力强、开销小&#xff0c;易于电路实…