Java 与设计模式(12):享元模式
一、定义
享元模式是一种结构型设计模式,旨在有效地共享对象以减少内存使用和提高性能。该模式的核心思想是通过共享尽可能多的相似对象来减少内存占用。它将对象分为可共享的内部状态和不可共享的外部状态。内部状态是对象的固有属性,可以在多个对象之间共享,而外部状态是对象的上下文相关属性,每个对象都是独立的。
通过共享内部状态,享元模式可以减少创建相似对象的数量,从而节省内存空间。当需要创建新对象时,可以首先检查是否已经存在具有相同内部状态的对象,如果存在,则可以直接返回共享的对象,而不是创建新的对象。这种共享对象的方式可以在大规模使用相似对象的场景中提高性能和效率。
需要注意的是,享元模式需要维护一个对象池或缓存来存储共享的对象,以便在需要时进行检索。同时,外部状态的管理也需要谨慎处理,确保每个对象在不同的上下文中都能正确地使用。
享元模式通过共享相似对象的内部状态来减少内存占用和提高性能,是一种常用的优化技术。
二、Java示例
import java.util.HashMap;
import java.util.Map;// 具体享元类
class ConcreteFlyweight {private String intrinsicState;public ConcreteFlyweight(String intrinsicState) {this.intrinsicState = intrinsicState;}public void operation(String extrinsicState) {System.out.println("Intrinsic State: " + intrinsicState);System.out.println("Extrinsic State: " + extrinsicState);}
}// 享元工厂类
class FlyweightFactory {private Map<String, ConcreteFlyweight> flyweights = new HashMap<>();public ConcreteFlyweight getFlyweight(String key) {if (flyweights.containsKey(key)) {return flyweights.get(key);} else {ConcreteFlyweight flyweight = new ConcreteFlyweight(key);flyweights.put(key, flyweight);return flyweight;}}
}// 客户端代码
public class Client {public static void main(String[] args) {FlyweightFactory factory = new FlyweightFactory();ConcreteFlyweight flyweight1 = factory.getFlyweight("shared");flyweight1.operation("state 1");ConcreteFlyweight flyweight2 = factory.getFlyweight("shared");flyweight2.operation("state 2");ConcreteFlyweight flyweight3 = factory.getFlyweight("unique");flyweight3.operation("state 3");}
}
在上述示例中,ConcreteFlyweight类表示具体的享元对象,包含一个内部状态intrinsicState。FlyweightFactory类作为享元工厂,维护一个对象池flyweights,用于存储共享的享元对象。
客户端代码通过FlyweightFactory获取享元对象,并调用其operation方法进行操作。当请求的享元对象已存在于对象池中时,直接返回共享的对象;否则,创建新的享元对象并添加到对象池中。
这样,通过共享相似对象的内部状态,可以减少创建对象的数量,节省内存空间。在示例中,flyweight1和flyweight2共享了相同的内部状态,而flyweight3是一个独立的对象。
三、优点
享元模式的优点包括:
-
减少内存占用:通过共享相似对象的内部状态,可以减少创建对象的数量,从而减少内存占用。
-
提高性能:由于减少了对象的数量,可以减少对象的创建和销毁过程,从而提高程序的性能。
-
提高对象复用性:通过共享对象,可以在不同的上下文中复用对象,避免重复创建相似的对象。
-
简化对象管理:享元模式将对象的内部状态和外部状态进行分离,使得对象的管理更加简单和清晰。
-
支持大规模对象共享:当系统中存在大量相似对象时,通过享元模式可以有效地管理和共享这些对象,提高系统的可扩展性和可维护性。
享元模式通过共享相似对象的内部状态,可以减少内存占用、提高性能和对象复用性,简化对象管理,并支持大规模对象共享。这使得享元模式成为一种有价值的优化技术。
四、缺点
享元模式的缺点包括:
-
对象共享可能导致线程安全问题:如果多个线程同时访问共享对象,并且修改了对象的外部状态,可能会导致线程安全问题。需要在使用享元对象时进行适当的同步控制。
-
对象池管理增加复杂性:享元模式需要维护一个对象池或缓存来存储共享对象,这增加了对象管理的复杂性。需要确保正确地管理对象的创建、共享和销毁,避免资源泄露或过度消耗。
-
对象共享可能降低系统灵活性:当对象的内部状态和外部状态耦合较高时,共享对象可能限制了系统的灵活性。如果需要修改共享对象的内部状态,可能会影响到其他共享该对象的地方。
-
需要额外的内部状态管理:享元模式将对象的内部状态和外部状态进行分离,需要额外的管理和维护内部状态的机制。这增加了一定的复杂性和开销。
享元模式在提高性能和减少内存占用方面有优势,但也需要考虑线程安全、对象管理复杂性以及灵活性等方面的问题。在使用时需要根据具体场景进行权衡和设计。
五、使用场景
享元模式适用于以下场景:
-
对象数量庞大且相似:当系统中存在大量相似的对象,并且这些对象可以共享部分或全部内部状态时,可以使用享元模式来减少对象的数量和内存占用。
-
对象的外部状态可分离:对象的外部状态可以被分离出来,并且可以通过参数传递给对象的方法。这样可以将对象的内部状态与外部状态分离,使得对象可以共享内部状态。
-
需要缓存或池化对象:如果需要频繁地创建和销毁对象,并且对象的创建和销毁过程较为耗时,可以使用享元模式来缓存或池化对象,提高性能。
-
系统需要支持大规模对象共享:当系统中存在大量相似对象,并且这些对象需要在不同的上下文中共享时,可以使用享元模式来管理和共享这些对象,提高系统的可扩展性和可维护性。
需要注意的是,使用享元模式需要权衡对象共享带来的线程安全问题、对象管理的复杂性以及灵活性的影响。在具体应用时,需要根据实际情况进行设计和优化。
六、注意事项
在使用享元模式时,需要注意以下几点:
-
线程安全性:如果多个线程同时访问共享对象,并且修改了对象的外部状态,可能会导致线程安全问题。需要在使用享元对象时进行适当的同步控制,确保线程安全。
-
对象池管理:享元模式需要维护一个对象池或缓存来存储共享对象,需要确保正确地管理对象的创建、共享和销毁。需要注意避免资源泄露或过度消耗。
-
内部状态和外部状态的划分:需要合理划分对象的内部状态和外部状态,确保内部状态可以共享,而外部状态可以通过参数传递给对象的方法。同时,需要注意内部状态和外部状态的耦合度,避免影响系统的灵活性。
-
对象的可变性:享元模式适用于对象的内部状态是不可变的情况。如果对象的内部状态是可变的,需要考虑如何处理共享对象的可变性,以及如何保证共享对象的一致性。
-
性能权衡:使用享元模式可以提高性能和减少内存占用,但也需要权衡对象共享带来的管理复杂性和灵活性的影响。在具体应用时,需要根据实际情况进行设计和优化。
使用享元模式需要综合考虑线程安全性、对象管理、内部状态和外部状态的划分、对象的可变性以及性能权衡等方面的问题。在具体应用时,需要根据实际需求和场景进行适当的设计和调整。
七、在spring 中的应用
在Spring源码中,享元模式被广泛应用于各个模块和组件中,以提高性能和减少内存占用。以下是一些Spring源码中使用享元模式的示例:
-
Bean对象的管理:在Spring的IoC容器中,Bean对象被视为享元对象。当容器启动时,会预先创建并缓存Bean对象,以便在需要时进行共享和复用。这样可以减少对象的创建和销毁开销,提高性能。
-
数据库连接池:Spring的JDBC模块中,使用享元模式管理数据库连接。连接池中的连接对象被视为享元对象,可以在多个线程之间共享和复用,避免频繁地创建和销毁连接,提高数据库操作的性能。
-
缓存管理:Spring的缓存模块中,使用享元模式管理缓存对象。缓存对象被视为享元对象,可以在多个请求之间共享和复用,避免重复计算和查询,提高系统的响应速度。
-
国际化资源管理:Spring的国际化模块中,使用享元模式管理国际化资源对象。国际化资源对象被视为享元对象,可以在多个地方共享和复用,避免重复加载和解析资源文件,提高国际化功能的性能。
需要注意的是,Spring框架中对享元模式的应用往往是隐式的,封装在各个模块和组件中,不会直接暴露给开发者。这样可以提供更加简洁和易用的API,同时隐藏了底层的实现细节。
相关文章:
Java 与设计模式(12):享元模式
一、定义 享元模式是一种结构型设计模式,旨在有效地共享对象以减少内存使用和提高性能。该模式的核心思想是通过共享尽可能多的相似对象来减少内存占用。它将对象分为可共享的内部状态和不可共享的外部状态。内部状态是对象的固有属性,可以在多个对象之…...
React配置代理(proxy)
使用axios进行请求,而配置代理过程。 第一种 在package.json中,添加proxy配置项,之后所有的请求都会指向该地址 但这种方法只能配置一次,也只有一个 示例: "proxy":"https://localhost:5000" 添加后&am…...
队列(Queue):先进先出的数据结构队列
栈与队列https://blog.csdn.net/qq_45467165/article/details/127958960?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127958960%22%2C%22source%22%3A%22qq_45467165%22%7D 队列(Queue)是一种常见的线…...
CentOS ens160 显示disconnected
使用nmcli device查看网卡状态,显示如图: 检查宿主机系统VMware DHCP Sevice和VMware NAT Sevice服务是否正常运行。 右键点击我的电脑管理按钮,打开计算机管理点击服务...
使用 ChatGPT 创建 PowerPoint 演示文稿
让 ChatGPT 成为您的助手来帮助您编写电子邮件很简单,因为众所周知,它非常能够生成文本。很明显,ChatGPT 无法帮助您做饭。但您可能想知道它是否可以生成文本以外的其他内容。在上一篇文章中,您了解到 ChatGPT 只能通过中间语言为您生成图形。在这篇文章中,您将了解使用中…...
matlab将数组值划分为两类
例如:大于0的处理为1,小于0的处理为-1. 当然,可以选择循环结构和选择结构,但是效率会很低。 这里直接使用逻辑语句完成。 % 不使用循环语句,将数组内值划分为两类 clc; clearvars; a[-0.1422 , -0.0433 , 0.1131 …...
【点击新增一个下拉框 与前一个内容一样 但不能选同一个值】
点击新增一个下拉框 与前一个内容一样 但不能选同一个值 主要是看下拉选择el-option的disabled,注意不要混淆 <el-form label-width"120px" :model"form" ref"form" style"color: #fff"><template v-for"(trapolicy, i…...
【Gitee提交pr】
Gitee提交pr 什么是pr怎样提交一个pr嘞? 什么是pr pr:指的是将自己的修改从自己的账号仓库dev下提交到官方账号仓库master下; 通俗来讲就是Gitee线上有属于自己的分支,然后本地在自己地分支修改完代码之后,提交到自己的线上分支&a…...
一款打工人必备的电脑端自律软件!!冲鸭打工人!!
你!有没有渴望进步!! 你!有没有渴望变强!!! 成为大佬!!!超越巨佬!!! 这就是一款为这样的你量身定做的程序:输入…...
【Vue框架】 router和route是什么关系
前言 之前没太注意,写着写着突然发现它们貌似不太一样,记录以下,回顾的看总结就好。 1、总结✨ route:当前激活路由的对象,用于访问和操作当前路由的信息 router:管理多个route的对象,整个应…...
整理mongodb文档:聚合管道
个人博客 整理mongodb文档:聚合管道 个人博客,求关注,电脑版看体验更加,如果不够清晰,请指出来,谢谢 文章概叙 文章主要通过几个常用的聚合表达式来介绍聚合管道的使用,以及从索引的角度来介绍聚合管道…...
Delphi 11.3 FMX 多设备平台中使用 TGrid 实现类似 TDBGrid 的效果
Delphi Firemonkey 中 TDBGrid 这个控件已经没有了。如何实现类似这个效果呢。其实可以用TGrid 来实现。以下用 11.3 来讲解。 查询里面用到的 connection 和 query 等控件那些一般的数据库用法,就不做过多描述了。请参考其他资料。 方法一.通过界面配置来实现 在…...
Qt-事件循环与QtConcurrent、QThread结合使用时注意的点
QEventLoop和QtConcurrent可以结合使用达到主线程ui不阻塞同步执行的效果,但是要小心避坑,查看如下代码: QEventLoop loop; QtConcurrent::run([&]() {doSomething();loop.quit(); }); loop.exec();上述写法存在两个问题: Q…...
基于MongoDB的空间数据存储与查询
一、概念说明 1.1 空间地理数据 MongoDB 中使用 GeoJSON对象 或 坐标对 描述空间地理数据。MongoDB使用 WGS84 参考系进行地理空间数据查询。 1、MongoDB支持空间数据的存储,数据类型需要限制为GeoJSON; 2、MongoDB可以为GeoJSON类型数据建立索引,提升空…...
jquery中pdf的上传、下载及excel导出
jquery中pdf的上传、下载及excel导出 1.PDF上传 pdfUpload2. pdf下载和excel导出用的一种方法,并且需要引入utils.js2.1PDF下载 pdfDownload2.2导出Excel excelExport 1.PDF上传 pdfUpload //PDF上传 pdfUpload window.pdfUploadfunction (obj){layer.open({type:…...
【MyBatis】:PageHelper分页插件与特殊字符处理
目录 一、PageHelper介绍 二、PageHelper使用 1. 导入pom依赖 2. Mybatis.cfg.xml 配置拦截器 3. 配置 Mapper.xml 4. 编写测试 三、特殊字符处理 1. 使用转义字符 2. 使用CDATA 区段 一、PageHelper介绍 PageHelper 是 Mybatis 的一个插件,这里就不扯了&a…...
C语言练习1(巩固提升)
C语言练习1 选择题 前言 “人生在勤,勤则不匮。”幸福不会从天降,美好生活靠劳动创造。全面建成小康社会的奋斗目标,为广大劳动群众指明了光明的未来;全面建成小康社会的历史任务,为广大劳动群众赋予了光荣的使命&…...
eCharts热力图Y轴左上角少一块
问题: 如图 在图例的左上角 Y轴会少一块 官方demo https://echarts.apache.org/examples/zh/editor.html?cheatmap-cartesian 事实上 把官方demo的左上角坐标 [ 6, 0, 1 ] 修改为 [ 6, 0, 0 ] 后 依旧会出现该问题 查遍文档 并无解释 也没有任何配置项可解决…...
RabbitMQ介绍
RabbitMQ的概念 RabbitMQ 是一个消息中间件:它接受并转发消息。你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放到快递站,快递员最终会把你的快递送到收件人那里,按照这种逻辑 RabbitMQ 是 一个快递…...
玩转软件|钉钉个人版内测启动:AI探索未来的工作方式
目录 前言 正文 AI为核心,个人效率为王! 指令中心,解锁AI技巧! 灵感Store,探索更多可能! 未来的AI,即将问世! 个人内测体验 前言 重磅消息:钉钉个人版在8月16日正…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
