当前位置: 首页 > news >正文

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类表示具体的享元对象,包含一个内部状态intrinsicStateFlyweightFactory类作为享元工厂,维护一个对象池flyweights,用于存储共享的享元对象。

客户端代码通过FlyweightFactory获取享元对象,并调用其operation方法进行操作。当请求的享元对象已存在于对象池中时,直接返回共享的对象;否则,创建新的享元对象并添加到对象池中。

这样,通过共享相似对象的内部状态,可以减少创建对象的数量,节省内存空间。在示例中,flyweight1flyweight2共享了相同的内部状态,而flyweight3是一个独立的对象。

三、优点

享元模式的优点包括:

  1. 减少内存占用:通过共享相似对象的内部状态,可以减少创建对象的数量,从而减少内存占用。

  2. 提高性能:由于减少了对象的数量,可以减少对象的创建和销毁过程,从而提高程序的性能。

  3. 提高对象复用性:通过共享对象,可以在不同的上下文中复用对象,避免重复创建相似的对象。

  4. 简化对象管理:享元模式将对象的内部状态和外部状态进行分离,使得对象的管理更加简单和清晰。

  5. 支持大规模对象共享:当系统中存在大量相似对象时,通过享元模式可以有效地管理和共享这些对象,提高系统的可扩展性和可维护性。

享元模式通过共享相似对象的内部状态,可以减少内存占用、提高性能和对象复用性,简化对象管理,并支持大规模对象共享。这使得享元模式成为一种有价值的优化技术。

四、缺点

享元模式的缺点包括:

  1. 对象共享可能导致线程安全问题:如果多个线程同时访问共享对象,并且修改了对象的外部状态,可能会导致线程安全问题。需要在使用享元对象时进行适当的同步控制。

  2. 对象池管理增加复杂性:享元模式需要维护一个对象池或缓存来存储共享对象,这增加了对象管理的复杂性。需要确保正确地管理对象的创建、共享和销毁,避免资源泄露或过度消耗。

  3. 对象共享可能降低系统灵活性:当对象的内部状态和外部状态耦合较高时,共享对象可能限制了系统的灵活性。如果需要修改共享对象的内部状态,可能会影响到其他共享该对象的地方。

  4. 需要额外的内部状态管理:享元模式将对象的内部状态和外部状态进行分离,需要额外的管理和维护内部状态的机制。这增加了一定的复杂性和开销。

享元模式在提高性能和减少内存占用方面有优势,但也需要考虑线程安全、对象管理复杂性以及灵活性等方面的问题。在使用时需要根据具体场景进行权衡和设计。

五、使用场景

享元模式适用于以下场景:

  1. 对象数量庞大且相似:当系统中存在大量相似的对象,并且这些对象可以共享部分或全部内部状态时,可以使用享元模式来减少对象的数量和内存占用。

  2. 对象的外部状态可分离:对象的外部状态可以被分离出来,并且可以通过参数传递给对象的方法。这样可以将对象的内部状态与外部状态分离,使得对象可以共享内部状态。

  3. 需要缓存或池化对象:如果需要频繁地创建和销毁对象,并且对象的创建和销毁过程较为耗时,可以使用享元模式来缓存或池化对象,提高性能。

  4. 系统需要支持大规模对象共享:当系统中存在大量相似对象,并且这些对象需要在不同的上下文中共享时,可以使用享元模式来管理和共享这些对象,提高系统的可扩展性和可维护性。

需要注意的是,使用享元模式需要权衡对象共享带来的线程安全问题、对象管理的复杂性以及灵活性的影响。在具体应用时,需要根据实际情况进行设计和优化。

六、注意事项

在使用享元模式时,需要注意以下几点:

  1. 线程安全性:如果多个线程同时访问共享对象,并且修改了对象的外部状态,可能会导致线程安全问题。需要在使用享元对象时进行适当的同步控制,确保线程安全。

  2. 对象池管理:享元模式需要维护一个对象池或缓存来存储共享对象,需要确保正确地管理对象的创建、共享和销毁。需要注意避免资源泄露或过度消耗。

  3. 内部状态和外部状态的划分:需要合理划分对象的内部状态和外部状态,确保内部状态可以共享,而外部状态可以通过参数传递给对象的方法。同时,需要注意内部状态和外部状态的耦合度,避免影响系统的灵活性。

  4. 对象的可变性:享元模式适用于对象的内部状态是不可变的情况。如果对象的内部状态是可变的,需要考虑如何处理共享对象的可变性,以及如何保证共享对象的一致性。

  5. 性能权衡:使用享元模式可以提高性能和减少内存占用,但也需要权衡对象共享带来的管理复杂性和灵活性的影响。在具体应用时,需要根据实际情况进行设计和优化。

使用享元模式需要综合考虑线程安全性、对象管理、内部状态和外部状态的划分、对象的可变性以及性能权衡等方面的问题。在具体应用时,需要根据实际需求和场景进行适当的设计和调整。

七、在spring 中的应用

在Spring源码中,享元模式被广泛应用于各个模块和组件中,以提高性能和减少内存占用。以下是一些Spring源码中使用享元模式的示例:

  1. Bean对象的管理:在Spring的IoC容器中,Bean对象被视为享元对象。当容器启动时,会预先创建并缓存Bean对象,以便在需要时进行共享和复用。这样可以减少对象的创建和销毁开销,提高性能。

  2. 数据库连接池:Spring的JDBC模块中,使用享元模式管理数据库连接。连接池中的连接对象被视为享元对象,可以在多个线程之间共享和复用,避免频繁地创建和销毁连接,提高数据库操作的性能。

  3. 缓存管理:Spring的缓存模块中,使用享元模式管理缓存对象。缓存对象被视为享元对象,可以在多个请求之间共享和复用,避免重复计算和查询,提高系统的响应速度。

  4. 国际化资源管理:Spring的国际化模块中,使用享元模式管理国际化资源对象。国际化资源对象被视为享元对象,可以在多个地方共享和复用,避免重复加载和解析资源文件,提高国际化功能的性能。

需要注意的是,Spring框架中对享元模式的应用往往是隐式的,封装在各个模块和组件中,不会直接暴露给开发者。这样可以提供更加简洁和易用的API,同时隐藏了底层的实现细节。

相关文章:

Java 与设计模式(12):享元模式

一、定义 享元模式是一种结构型设计模式&#xff0c;旨在有效地共享对象以减少内存使用和提高性能。该模式的核心思想是通过共享尽可能多的相似对象来减少内存占用。它将对象分为可共享的内部状态和不可共享的外部状态。内部状态是对象的固有属性&#xff0c;可以在多个对象之…...

React配置代理(proxy)

使用axios进行请求&#xff0c;而配置代理过程。 第一种 在package.json中&#xff0c;添加proxy配置项,之后所有的请求都会指向该地址 但这种方法只能配置一次&#xff0c;也只有一个 示例&#xff1a; "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 队列&#xff08;Queue&#xff09;是一种常见的线…...

CentOS ens160 显示disconnected

使用nmcli device查看网卡状态&#xff0c;显示如图&#xff1a; 检查宿主机系统VMware DHCP Sevice和VMware NAT Sevice服务是否正常运行。 右键点击我的电脑管理按钮&#xff0c;打开计算机管理点击服务...

使用 ChatGPT 创建 PowerPoint 演示文稿

让 ChatGPT 成为您的助手来帮助您编写电子邮件很简单,因为众所周知,它非常能够生成文本。很明显,ChatGPT 无法帮助您做饭。但您可能想知道它是否可以生成文本以外的其他内容。在上一篇文章中,您了解到 ChatGPT 只能通过中间语言为您生成图形。在这篇文章中,您将了解使用中…...

matlab将数组值划分为两类

例如&#xff1a;大于0的处理为1&#xff0c;小于0的处理为-1. 当然&#xff0c;可以选择循环结构和选择结构&#xff0c;但是效率会很低。 这里直接使用逻辑语句完成。 % 不使用循环语句&#xff0c;将数组内值划分为两类 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嘞&#xff1f; 什么是pr pr:指的是将自己的修改从自己的账号仓库dev下提交到官方账号仓库master下&#xff1b; 通俗来讲就是Gitee线上有属于自己的分支&#xff0c;然后本地在自己地分支修改完代码之后&#xff0c;提交到自己的线上分支&a…...

一款打工人必备的电脑端自律软件!!冲鸭打工人!!

你&#xff01;有没有渴望进步&#xff01;&#xff01; 你&#xff01;有没有渴望变强&#xff01;&#xff01;&#xff01; 成为大佬&#xff01;&#xff01;&#xff01;超越巨佬&#xff01;&#xff01;&#xff01; 这就是一款为这样的你量身定做的程序&#xff1a;输入…...

【Vue框架】 router和route是什么关系

前言 之前没太注意&#xff0c;写着写着突然发现它们貌似不太一样&#xff0c;记录以下&#xff0c;回顾的看总结就好。 1、总结✨ route&#xff1a;当前激活路由的对象&#xff0c;用于访问和操作当前路由的信息 router&#xff1a;管理多个route的对象&#xff0c;整个应…...

整理mongodb文档:聚合管道

个人博客 整理mongodb文档:聚合管道 个人博客&#xff0c;求关注&#xff0c;电脑版看体验更加&#xff0c;如果不够清晰&#xff0c;请指出来&#xff0c;谢谢 文章概叙 文章主要通过几个常用的聚合表达式来介绍聚合管道的使用&#xff0c;以及从索引的角度来介绍聚合管道…...

Delphi 11.3 FMX 多设备平台中使用 TGrid 实现类似 TDBGrid 的效果

Delphi Firemonkey 中 TDBGrid 这个控件已经没有了。如何实现类似这个效果呢。其实可以用TGrid 来实现。以下用 11.3 来讲解。 查询里面用到的 connection 和 query 等控件那些一般的数据库用法&#xff0c;就不做过多描述了。请参考其他资料。 方法一.通过界面配置来实现 在…...

Qt-事件循环与QtConcurrent、QThread结合使用时注意的点

QEventLoop和QtConcurrent可以结合使用达到主线程ui不阻塞同步执行的效果&#xff0c;但是要小心避坑&#xff0c;查看如下代码&#xff1a; QEventLoop loop; QtConcurrent::run([&]() {doSomething();loop.quit(); }); loop.exec();上述写法存在两个问题&#xff1a; Q…...

基于MongoDB的空间数据存储与查询

一、概念说明 1.1 空间地理数据 MongoDB 中使用 GeoJSON对象 或 坐标对 描述空间地理数据。MongoDB使用 WGS84 参考系进行地理空间数据查询。 1、MongoDB支持空间数据的存储&#xff0c;数据类型需要限制为GeoJSON; 2、MongoDB可以为GeoJSON类型数据建立索引&#xff0c;提升空…...

jquery中pdf的上传、下载及excel导出

jquery中pdf的上传、下载及excel导出 1.PDF上传 pdfUpload2. pdf下载和excel导出用的一种方法&#xff0c;并且需要引入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 的一个插件&#xff0c;这里就不扯了&a…...

C语言练习1(巩固提升)

C语言练习1 选择题 前言 “人生在勤&#xff0c;勤则不匮。”幸福不会从天降&#xff0c;美好生活靠劳动创造。全面建成小康社会的奋斗目标&#xff0c;为广大劳动群众指明了光明的未来&#xff1b;全面建成小康社会的历史任务&#xff0c;为广大劳动群众赋予了光荣的使命&…...

eCharts热力图Y轴左上角少一块

问题&#xff1a; 如图 在图例的左上角 Y轴会少一块 官方demo https://echarts.apache.org/examples/zh/editor.html?cheatmap-cartesian 事实上 把官方demo的左上角坐标 [ 6, 0, 1 ] 修改为 [ 6, 0, 0 ] 后 依旧会出现该问题 查遍文档 并无解释 也没有任何配置项可解决…...

RabbitMQ介绍

RabbitMQ的概念 RabbitMQ 是一个消息中间件&#xff1a;它接受并转发消息。你可以把它当做一个快递站点&#xff0c;当你要发送一个包裹时&#xff0c;你把你的包裹放到快递站&#xff0c;快递员最终会把你的快递送到收件人那里&#xff0c;按照这种逻辑 RabbitMQ 是 一个快递…...

玩转软件|钉钉个人版内测启动:AI探索未来的工作方式

目录 前言 正文 AI为核心&#xff0c;个人效率为王&#xff01; 指令中心&#xff0c;解锁AI技巧&#xff01; 灵感Store&#xff0c;探索更多可能&#xff01; 未来的AI&#xff0c;即将问世&#xff01; 个人内测体验 前言 重磅消息&#xff1a;钉钉个人版在8月16日正…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...