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

【设计模式】Java 设计模式之享元模式(Flyweight)

享元模式(Flyweight)的深入分析

一、概述

享元模式是一种结构型设计模式,它提供了一种有效的方式来减少在大量对象中产生的内存开销。通过共享尽可能多的对象,享元模式可以使程序更高效地使用内存。享元模式常用于那些创建对象实例的成本非常高昂的场景,例如,当对象的数量非常大,而对象的某些状态又可以在多个上下文中共享时,这种模式就非常有用。

二、模式结构

享元模式主要包含以下三种角色:

  1. Flyweight(享元):抽象享元类,声明一个接口,通过它可以接受并作用于外部状态。
  2. ConcreteFlyweight(具体享元):实现Flyweight接口,并为内部状态增加存储空间。ConcreteFlyweight对象必须是可共享的。它的内部状态必须独立于它的客户端,这样多个客户端才可以共享一个ConcreteFlyweight对象。
  3. 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]

四、优缺点分析

优点

  1. 显著减少对象的数量,节省内存空间。
  2. 由于减少了对象的数量,同时也减少了创建对象所需的时间,因此提高了系统的性能。

缺点

  1. 为了使对象可共享,需要将一些状态外部化,这使得程序逻辑可能变得复杂。
  2. 如果对象的状态大部分不能外部化,则享元模式可能不适用。

五、常见应用场景

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

  1. 大量细粒度对象:当系统中存在大量相似的对象,且这些对象的状态可以通过外部参数进行区分时,可以使用享元模式来减少对象的数量。
  2. 字符串存储:在字符串池或字符串表中,可以使用享元模式来共享常用的字符串,避免重复创建。
  3. 图形渲染:在图形渲染系统中,可以使用享元模式来共享颜色、字体等对象,减少内存消耗。

六、深入应用案例解读

以游戏开发为例,让我们进一步探讨享元模式在实际应用中的详细实现和优势。

在游戏开发中,角色的皮肤、装备、技能等通常具有大量的相似或重复数据。这些数据如果都单独存储,将会消耗大量的内存资源。通过使用享元模式,我们可以将这些共享的数据提取出来,只存储一份,而不同的角色实例则通过引用这些共享数据来减少内存占用。

首先,我们定义一个享元类(Flyweight),它包含了角色的皮肤、装备等共享数据。这些共享数据是内在的、不变的,并且可以被多个角色实例所共享。

然后,我们创建一个享元工厂(FlyweightFactory),用于管理享元对象的创建和存储。工厂内部使用一个哈希表或类似的数据结构来存储已经创建的享元对象。当需要获取一个享元对象时,工厂首先检查哈希表中是否存在对应的对象。如果存在,则直接返回该对象;如果不存在,则创建一个新的享元对象并将其存储在哈希表中。

在游戏中,每个角色实例在创建时,并不直接包含皮肤、装备等数据的完整副本,而是持有对相应享元对象的引用。这样,即使我们有大量的角色实例,它们共享的皮肤、装备等数据也只需要存储一份,从而极大地减少了内存消耗。

此外,享元模式还可以结合其他设计模式来进一步优化内存使用。例如,可以使用原型模式(Prototype)来快速复制享元对象,而无需每次都重新创建。同时,为了支持不同的角色状态或行为,我们可以将角色的外部状态(如位置、生命值等)与享元对象分离,这样即使享元对象是共享的,每个角色实例仍然可以拥有自己独特的外部状态。

通过应用享元模式,我们可以显著减少游戏开发中的内存消耗,提高游戏的运行效率。同时,这也使得游戏能够支持更多的角色和更丰富的装备皮肤,提升了游戏的可玩性和用户体验。

需要注意的是,在使用享元模式时,我们需要仔细分析系统的需求和数据结构,确保共享的数据是合理的,并且不会导致程序逻辑变得复杂或难以理解。同时,我们还需要注意线程安全问题,特别是在多线程环境下共享对象时,需要采取适当的同步措施来避免数据冲突和不一致的问题。

综上所述,享元模式是一种非常实用的设计模式,它可以帮助我们在大量相似对象中减少内存消耗并提高性能。通过合理地应用享元模式,我们可以构建出更加高效、可扩展和可维护的软件系统。

七、享元模式的变体及扩展

在实际应用中,享元模式可以根据具体需求进行变体设计和扩展,以适应更复杂的场景。

  1. 带有上下文的享元
    在某些情况下,享元对象可能需要访问一些外部状态或上下文信息。为了支持这种情况,我们可以为享元对象添加一个上下文参数,使其在操作时能够访问到这些外部状态。这样,享元对象就可以根据不同的上下文来执行不同的操作,增加了灵活性。

  2. 不可变享元
    为了确保享元对象的安全性和一致性,我们可以将其设计为不可变的。这意味着一旦享元对象被创建并初始化后,其内部状态就不能再被修改。通过这样做,我们可以避免由于并发访问或错误操作导致的数据不一致问题。当然,这也要求我们在设计享元对象时,要仔细考虑其状态是否真正需要被共享和不可变。

  3. 享元池
    除了使用享元工厂来管理享元对象的创建和存储外,我们还可以引入享元池的概念。享元池是一个预先创建并存储了大量享元对象的容器。当需要获取享元对象时,直接从享元池中获取即可,而无需每次都通过享元工厂来创建。这样可以进一步提高性能,减少创建对象的开销。当然,享元池的大小和管理策略需要根据具体的应用场景来设计和调整。

八、总结

享元模式是一种用于减少对象数量并节省内存空间的设计模式。通过共享对象的内部状态,我们可以显著减少系统中的对象数量,提高性能。然而,使用享元模式也需要注意权衡共享与复杂度之间的关系,确保设计合理且易于维护。

在实际应用中,我们可以根据具体需求对享元模式进行变体设计和扩展,以适应不同的场景。通过结合其他设计模式,如原型模式、单例模式等,我们可以构建出更加高效、可扩展和可维护的软件系统。

最后,需要强调的是,设计模式并不是银弹,它们只是解决特定问题的工具。在应用享元模式时,我们应该根据具体情况进行分析和判断,确保使用得当并带来实际效益。

相关文章:

【设计模式】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&…...

html5播放flv视频

参考:flv-h265 - npmHTML5 FLV Player. Latest version: 1.7.0, last published: 6 months ago. Start using flv-h265 in your project by running npm i flv-h265. There are no other projects in the npm registry using flv-h265.https://www.npmjs.com/packag…...

【知识简略】 简单理解SpringCloud微服务架构:服务注册发现、配置中心、限流、熔断、降级、网关路由等

主要介绍Nacos那一套。 目录 微服务架构1.服务注册发现2.配置中心3.限流、熔断、降级4.网关路由 微服务架构 Spring Cloud 微服务架构中,Nacos 提供了一系列核心组件和服务治理功能,以下是对 Nacos 中涉及的相关组件及其功能的详细解释: 1.…...

福派斯课堂:选择黑背犬的狗粮时需要注意哪些细节?

亲爱的狗友们,选择适合黑背犬的狗粮可不是一件小事哦!🐾 毕竟,黑背犬作为活泼、聪明的犬种,它们的饮食需求可是很特别的。接下来,就让我们一起探讨一下选择黑背犬狗粮时需要注意的细节吧! 1️⃣…...

Python QT 之PySide6简单入门

目录 1.开发环境配置 1.1 下载PySide6 2.2 配置pycharm相关快捷方式 PySide6_Designer - QT Designer 设计UI PySide6_UIC - 将QT Designer生成的UI文件转换为python文件 PySide6_RCC - 将RCC文件转换为python文件 2.第一个开发实例 2.1 QT desiger设计界面 2.2 将ui文…...

美团大规模KV存储挑战与架构实践

KV 存储作为美团一项重要的在线存储服务,承载了在线服务每天万亿级的请求量,并且保持着 99.995% 的服务可用性。在 DataFunSummit 2023 数据基础架构峰会上,我们分享了《美团大规模 KV 存储挑战与架构实践》,本文为演讲内容的整理…...

计算机基础1-汇编基础

汇编语言是一种低级的计算机语言,它直接与计算机硬件进行交互。在汇编语言中,指令由一系列助记符(mnemonic)组成,用于执行特定的操作,如数据传输、算术运算和控制流程等。每个指令都对应着一条机器码&#…...

六、项目进度管理

六、项目进度管理 根据项目的范围进行项目的进度管理 项目进度管理主要包含以下几个项目管理过程: 规划进度管理定义活动排列活动顺序估算活动持续时间制定进度计划控制进度 1、规划进度管理 ​ 规划进度管理是为规划、编制、管理、执行和控制项目进度而制定政策、程序和文…...

java操作HBase

创建一个学生信息表,用来存储学生的姓名(姓名作为行键,且假设姓名不会重复)以及考试成绩,其中考试成绩(score)是一个列族,存储了各个科目的考试成绩。然后向student中添加数据 1、HB…...

【MATLAB】语音信号识别与处理:移动中位数滤波算法去噪及谱相减算法呈现频谱

1 基本定义 移动中位数滤波算法是一种基于中位数的滤波方法,它通过对信号进行滑动窗口处理,每次取窗口内的中位数作为当前点的估计值,以去除噪声。该算法的主要思想是利用中位数的鲁棒性,对信号中的噪声进行有效的消除。 具体来说…...

浏览器 实现文件下载 完成回调 兼容ie11

首先保证 改文件资源能够通过get请求或者 post请求拿到,基于此基础上我们可以实现得知下载完成后的回调 代码如下 const getFileAndCallback (url, callback) > {//定义执行作用域const that this;//首先 初始化一个原生ajax对象const xhr new XMLHttpReques…...