【设计模式】Java 设计模式之享元模式(Flyweight)
享元模式(Flyweight)的深入分析
一、概述
享元模式是一种结构型设计模式,它提供了一种有效的方式来减少在大量对象中产生的内存开销。通过共享尽可能多的对象,享元模式可以使程序更高效地使用内存。享元模式常用于那些创建对象实例的成本非常高昂的场景,例如,当对象的数量非常大,而对象的某些状态又可以在多个上下文中共享时,这种模式就非常有用。
二、模式结构
享元模式主要包含以下三种角色:
- Flyweight(享元):抽象享元类,声明一个接口,通过它可以接受并作用于外部状态。
- ConcreteFlyweight(具体享元):实现Flyweight接口,并为内部状态增加存储空间。ConcreteFlyweight对象必须是可共享的。它的内部状态必须独立于它的客户端,这样多个客户端才可以共享一个ConcreteFlyweight对象。
- FlyweightFactory(享元工厂):创建并管理享元对象。它确保合理地共享享元对象,当用户请求一个享元对象时,Factory对象会检查系统中是否已经有一个合适的对象,如果有,Factory对象就提供已经存在的对象;如果没有,Factory对象就创建一个新的对象。
三、实现方式
在实现享元模式时,我们通常会使用哈希表或字典来存储已经创建的享元对象,以便快速检索和共享。下面是一个简单的Python代码示例:
class Flyweight:def __init__(self, intrinsic_state):self.intrinsic_state = intrinsic_statedef operation(self, extrinsic_state):pass # 这里根据具体需求实现操作class FlyweightFactory:_flyweights = {}@staticmethoddef get_flyweight(intrinsic_state):if intrinsic_state not in FlyweightFactory._flyweights:FlyweightFactory._flyweights[intrinsic_state] = Flyweight(intrinsic_state)return FlyweightFactory._flyweights[intrinsic_state]
四、优缺点分析
优点:
- 显著减少对象的数量,节省内存空间。
- 由于减少了对象的数量,同时也减少了创建对象所需的时间,因此提高了系统的性能。
缺点:
- 为了使对象可共享,需要将一些状态外部化,这使得程序逻辑可能变得复杂。
- 如果对象的状态大部分不能外部化,则享元模式可能不适用。
五、常见应用场景
享元模式常用于以下场景:
- 大量细粒度对象:当系统中存在大量相似的对象,且这些对象的状态可以通过外部参数进行区分时,可以使用享元模式来减少对象的数量。
- 字符串存储:在字符串池或字符串表中,可以使用享元模式来共享常用的字符串,避免重复创建。
- 图形渲染:在图形渲染系统中,可以使用享元模式来共享颜色、字体等对象,减少内存消耗。
六、深入应用案例解读
以游戏开发为例,让我们进一步探讨享元模式在实际应用中的详细实现和优势。
在游戏开发中,角色的皮肤、装备、技能等通常具有大量的相似或重复数据。这些数据如果都单独存储,将会消耗大量的内存资源。通过使用享元模式,我们可以将这些共享的数据提取出来,只存储一份,而不同的角色实例则通过引用这些共享数据来减少内存占用。
首先,我们定义一个享元类(Flyweight),它包含了角色的皮肤、装备等共享数据。这些共享数据是内在的、不变的,并且可以被多个角色实例所共享。
然后,我们创建一个享元工厂(FlyweightFactory),用于管理享元对象的创建和存储。工厂内部使用一个哈希表或类似的数据结构来存储已经创建的享元对象。当需要获取一个享元对象时,工厂首先检查哈希表中是否存在对应的对象。如果存在,则直接返回该对象;如果不存在,则创建一个新的享元对象并将其存储在哈希表中。
在游戏中,每个角色实例在创建时,并不直接包含皮肤、装备等数据的完整副本,而是持有对相应享元对象的引用。这样,即使我们有大量的角色实例,它们共享的皮肤、装备等数据也只需要存储一份,从而极大地减少了内存消耗。
此外,享元模式还可以结合其他设计模式来进一步优化内存使用。例如,可以使用原型模式(Prototype)来快速复制享元对象,而无需每次都重新创建。同时,为了支持不同的角色状态或行为,我们可以将角色的外部状态(如位置、生命值等)与享元对象分离,这样即使享元对象是共享的,每个角色实例仍然可以拥有自己独特的外部状态。
通过应用享元模式,我们可以显著减少游戏开发中的内存消耗,提高游戏的运行效率。同时,这也使得游戏能够支持更多的角色和更丰富的装备皮肤,提升了游戏的可玩性和用户体验。
需要注意的是,在使用享元模式时,我们需要仔细分析系统的需求和数据结构,确保共享的数据是合理的,并且不会导致程序逻辑变得复杂或难以理解。同时,我们还需要注意线程安全问题,特别是在多线程环境下共享对象时,需要采取适当的同步措施来避免数据冲突和不一致的问题。
综上所述,享元模式是一种非常实用的设计模式,它可以帮助我们在大量相似对象中减少内存消耗并提高性能。通过合理地应用享元模式,我们可以构建出更加高效、可扩展和可维护的软件系统。
七、享元模式的变体及扩展
在实际应用中,享元模式可以根据具体需求进行变体设计和扩展,以适应更复杂的场景。
-
带有上下文的享元:
在某些情况下,享元对象可能需要访问一些外部状态或上下文信息。为了支持这种情况,我们可以为享元对象添加一个上下文参数,使其在操作时能够访问到这些外部状态。这样,享元对象就可以根据不同的上下文来执行不同的操作,增加了灵活性。 -
不可变享元:
为了确保享元对象的安全性和一致性,我们可以将其设计为不可变的。这意味着一旦享元对象被创建并初始化后,其内部状态就不能再被修改。通过这样做,我们可以避免由于并发访问或错误操作导致的数据不一致问题。当然,这也要求我们在设计享元对象时,要仔细考虑其状态是否真正需要被共享和不可变。 -
享元池:
除了使用享元工厂来管理享元对象的创建和存储外,我们还可以引入享元池的概念。享元池是一个预先创建并存储了大量享元对象的容器。当需要获取享元对象时,直接从享元池中获取即可,而无需每次都通过享元工厂来创建。这样可以进一步提高性能,减少创建对象的开销。当然,享元池的大小和管理策略需要根据具体的应用场景来设计和调整。
八、总结
享元模式是一种用于减少对象数量并节省内存空间的设计模式。通过共享对象的内部状态,我们可以显著减少系统中的对象数量,提高性能。然而,使用享元模式也需要注意权衡共享与复杂度之间的关系,确保设计合理且易于维护。
在实际应用中,我们可以根据具体需求对享元模式进行变体设计和扩展,以适应不同的场景。通过结合其他设计模式,如原型模式、单例模式等,我们可以构建出更加高效、可扩展和可维护的软件系统。
最后,需要强调的是,设计模式并不是银弹,它们只是解决特定问题的工具。在应用享元模式时,我们应该根据具体情况进行分析和判断,确保使用得当并带来实际效益。
相关文章:
【设计模式】Java 设计模式之享元模式(Flyweight)
享元模式(Flyweight)的深入分析 一、概述 享元模式是一种结构型设计模式,它提供了一种有效的方式来减少在大量对象中产生的内存开销。通过共享尽可能多的对象,享元模式可以使程序更高效地使用内存。享元模式常用于那些创建对象实…...

异次元发卡源码系统/荔枝发卡V3.0二次元风格发卡网全开源源码
– 支付系统,已经接入易支付及Z支付免签接口。 – 云更新,如果系统升级新版本,你无需进行繁琐操作,只需要在你的店铺后台就可以无缝完成升级。 – 商品销售,支持商品配图、会员价、游客价、邮件通知、卡密预选&#…...

腾讯春招后端一面(八股篇)
前言 前几天在网上发了腾讯面试官问的一些问题,好多小伙伴关注,今天对这些问题写个具体答案,博主好久没看八股了,正好复习一下。 面试手撕了三道算法,这部分之后更,喜欢的小伙伴可以留意一下我的账号。 1…...

“风口”上的量化大厂“绣球”抛向中低频人才
量化人才这几年是人才舞台上的“香饽饽”。 遵循着低频不如高频、小厂不如大厂的薪资逻辑,各路人才被各路机构“哄抢”,薪资一路走高。 但2024年的“信号”再强烈不过——量化大厂们到了改变的时候了。 而量化大厂们显然对此已“心知肚明”....... “…...
obdiag如何实现一键采集20+故障场景的诊断信息——《OceanBase诊断系列》之九
作者简介:靖顺,OcenaBase 开发工程师,专注于数据库诊断与调优 1. 前言 在2024年初,我与一线运维人员交流时,他们纷纷提及在运维过程中遭遇的难题——OceanBase出现问题时,排查工作不容易,有时需…...

Cookie和Session的获取方法
1、Cookie的简单获取方法(可以获取到所有的cookie) (1)在参数里还有HttpServletResponse response这些,这些都是内置对象需要就拿不需要就删掉就可以,在这里我们用到的是HttpServletRequest request &…...
旅游市场游客满意度调查报告
民安智库开展游客满意度调查主要通过问卷调查的方式进行,在设计问卷时,应确保问题覆盖游客在某省旅游过程中可能遇到的各个方面,包括交通、住宿、餐饮、旅游景点、导游服务等。此外,还可以设置一些开放性问题,让游客提…...
为什么选用python开发web?
目前,不少公司在用python做web开发,前司用pythonflask做内容审核的后端。 java和php在web开发领域积累较久,有丰富的web开发生态组件可以使用,性能稳定,扩展性强,这个是事实,从这方面来讲&…...

C# Chart曲线控件专题
1.控件基本设置 chart1.ChartAreas[0].AxisY.IsStartedFromZero false; //设置Y轴自适应chart1.Series["瞬时值"].BorderWidth 2; // 设置曲线宽度为2个像素,注意[]中写入的Series的Namechart1.Series["瞬时值"].Color Color.Red; // 设置曲…...

Spring:StopWatch
文章目录 一、介绍二、使用1、导入相关的Spring包2、创建StopWatch实例和开始计时3、停止计时4、获取时间5、获取任务详情6、分阶段计时7、获取总耗时与各阶段耗时 三、案例 一、介绍 在Spring框架中,StopWatch类通常用于测量代码块的执行时间。您可以使用StopWatc…...

考研C语言复习进阶(5)
目录 1. 为什么使用文件 2. 什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 3. 文件的打开和关闭 3.1 文件指针 3.2 文件的打开和关闭 4. 文件的顺序读写 编辑 编辑 4.1 对比一组函数: 编辑 5. 文件的随机读写 5.1 fseek 5.2 ftell 5.3 rewind…...
[uni-app] 小程序码转为二维码, 小程序解析此码获取数据
小程序码缩小后太细, 不好扫, 还是改成二维码扫 记录解析该二维码 onLoad(e) {if (e.shareTimeline) { // 以单页面启动-朋友圈分享出的单页面this.shareTimeline e.shareTimeline;let param {certId: e.certId,uid: e.uid,unionid: e.unionid,openid: e.openid,}this.initD…...

【四 (3)数据可视化之 Seaborn 常用图表及代码实现 】
目录 文章导航一、介绍二、安装Seaborn三、导入Seaborn四、设置可以中文显示五、占比类图表1、饼图2、环形图 六、比较排序类1、条形图2、箱线图3、小提琴图 七、趋势类图表1、折线图 八、频率分布类1、直方图 九、关系类图表1、散点图2、成对关系图3、热力图 文章导航 【一 简…...

ASP.NET-Server.HtmlEncode
目录 背景: 1.转义特殊字符: 2.防止跨站脚本攻击(XSS): 3.确保输出安全性: 4.保留原始文本形式: 5.与用户输入交互安全: 实例说明: 不用Server.HtmlEncode 效果展示: 用Server.HtmlEnc…...
Linux下进行JavaEE开发-安装JDK、Tomcat、MySQL
目录 JDKTomcatMySQL JDK 安装JDK步骤: 1、创建目录mkdir /opt/jdk 2、将jdk压缩包通过xftp6上传到该目录 3、cd /opt/jdk 4、tar -zxvf jdk-8u151-linux-x64.tar.gz 5、mkdir /usr/local/java 6、mv /opt/jdk/jdk1.8.0_151 /usr/local/java 7、修改环境变量…...
视频和图像编码标准或格式的发展关系
MPEG-2 继承 MPEG-1: MPEG-2 是 MPEG-1 的继任者,用于更高质量和分辨率的视频传输,如 DVD 和数字电视。 MPEG-4 继承 MPEG-2: MPEG-4 在 MPEG-2 的基础上增加了更多的功能和灵活性,适用于多媒体交互和网络传输。 H.2…...

移动云行动:5.5G技术引领数字化转型
刚刚结束的全国两会上,有人大代表建议应尽快发挥5G-A(5.5G)优势,加快试点城市布局。此前,中国移动已宣布将在300多个城市启动5.5G商用部署。在通信技术的历史长河中,4G改变了我们的生活方式,而5…...

Git如何与Gitee连接(主) , Git的基础使用方式简述(次)
作者前言 本章默认读者已经下好了git并拥有gitee账号,如果这两步没有完成的话,可以先去下载和注册账号接着继续阅读,由于写这篇博客的时候更关注的是怎么连接,所以先展示需要的部分,后面会介绍git的一些基本使用方法&…...
使用VLC实现自动播放视频
VLC是一款开源的多媒体播放器,它支持大量的视频和音频格式,并且具有强大的脚本和编程接口。虽然VLC本身并没有内置的编程语言,但你可以通过其命令行接口或Lua脚本来实现自动化播放视频的功能。 以下是一个简单的示例,展示如何使用…...
KY199 查找
描述: 输入数组长度 n 输入数组 a[1…n] 输入查找个数m 输入查找数字b[1…m] 输出 YES or NO 查找有则YES 否则NO 。 输入描述: 输入有多组数据。 每组输入n,然后输入n个整数,再输入m,然后再输入m个整数(1&…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

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…...