【设计模式】结构型设计模式之 享元模式
文章目录
- 介绍
- 关键概念
- 应用举例
- 象棋游戏共享棋子对象
- 文本编辑器中文字格式设计成享元模式
- 享元模式在 Java 中的应用
- 享元模式在包装类缓存中的应用
- 享元模式在 String 中的应用
- 对比
- 享元模式和单例模式的区别
- 享元模式与缓存的区别
- 总结
- 优点
- 缺点
介绍
享元模式,”享元“ 就是被共享的单元。享元模式的意图就是复用对象节省内存,应用的前提是被共享的对象是不可变的对象。
将对象设计成享元,保留一份实例供多处代码引用这样能减少内存中对象的数量,不允许修改是因为避免一出修改影响其他使用他的代码。
关键概念
- 享元(Flyweight):这是模式中的核心对象,可以被多个客户端共享。享元对象需要保持内部状态(Internal State)的共享,而外部状态(External State)则由客户端在使用时传入。
- 内部状态(Internal State):存储在享元对象内部,可以被共享,不随环境改变而改变的状态。
- 外部状态(External State):随环境改变而改变、不能共享的状态,由客户端传入享元对象,以便在运行时根据外部状态来区分不同的享元实例。
- 工厂(Factory):负责创建和管理享元对象,确保有效地复用享元对象,通常会使用缓存来存储已经创建的享元对象,以避免重复创建。
应用举例
象棋游戏共享棋子对象
问题:如果每个棋子都包含 id、文本、颜色、横坐标、纵坐标属性。并且每个游戏房间都有一个棋盘,那么如果游戏大厅中有成千上万个棋盘和对应的棋子。那么将创建大量的棋子对象。
方案:利用享元模式,象棋的棋子的一些属性,例如 id、颜色、文本都是固定不变的,下棋时每个棋盘的棋子也是一样的。所以只需要让棋子对象中保存 id、颜色、文本后被所有棋盘共享即可。每个房间只需要保存棋子的 id 和位置。这样就能节省大量的内存。
文本编辑器中文字格式设计成享元模式
一个文本编辑器,每个输入的字符都可以单独调整文本样式,如果给每个字符都保存一个字符样式对象那么十分浪费内存。并且文本编辑器中,一篇文本往往只有少量的几个文本格式所以设计成享元模式能节省大量内存。
/*** 文本样式类** @author Jean* @date 2024/06/04*/
@Getter
public class CharsetStyle {private int font;private int fontSize;private int colorRgb;public CharsetStyle(int font, int fontSize, int colorRgb) {this.font = font;this.fontSize = fontSize;this.colorRgb = colorRgb;}@Overridepublic boolean equals(Object obj) {if (!(obj instanceof CharsetStyle)) {return false;}CharsetStyle other = (CharsetStyle) obj;return other.font == this.font && this.fontSize == other.fontSize && this.colorRgb == other.colorRgb;}/*** 重写了equals一般要重写hashcode方法* 1. 如果两个对象根据 equals 方法判断是相等的,那么它们的 hashCode 方法必须返回相同的值。* 2. 如果两个对象根据 equals 方法判断是不相等的,那么它们的 hashCode 方法不必返回不同的值,但建议这样做以提高散列表(如 HashMap)的性能。* 违反这些规则可能会导致你的类在集合(尤其是基于散列的集合,如 HashSet 和 HashMap)中的行为不符合预期,比如无法正确识别已存在的元素或者影响集合的性能。因此,重写 equals 时配套重写 hashCode 是一种最佳实践。** @return int*/@Overridepublic int hashCode() {// 使用常数乘法、位移等操作来组合字段,以生成独特的哈希值int result = 17;result = 31 * result + font;result = 31 * result + fontSize;result = 31 * result + colorRgb;return result;}
}
/*** 文本样式工厂** @author Jean* @date 2024/06/04*/
public class CharacterStyleFactory {/*** 用来共享的文本样式*/private static final Set<CharsetStyle> styles = ConcurrentHashMap.newKeySet();/*** 获取样式的工厂** @param font* @param fontSize* @param colorRgb* @return {@link CharsetStyle}*/public static CharsetStyle getCharsetStype(int font, int fontSize, int colorRgb) {CharsetStyle charsetStyle = new CharsetStyle(font, fontSize, colorRgb);for (CharsetStyle style : styles) {if (style.equals(charsetStyle)) {return style;}}styles.add(charsetStyle);return charsetStyle;}}
享元模式在 Java 中的应用
享元模式在包装类缓存中的应用
Integer i1=56;
Integer i2=56;
Integer i3=129;
Integer i4=129;
System.out.pringln(i1==i2); //输出true
System.out.pringln(i3==i4); //输出false
例如上面的代码,会先输出 true 再输出 false
- i1 和 i2 自动装箱实际上调用的是 Integer.valueOf()方法,对应的自动拆箱的时候实际上调用的 Integer.intValue()方法。
- 在 Integer.valueOf 方法中就用到了享元模式,这个方法中实际上是从一个 Integer 的内部类 IntegerCache.cache 中获取缓存好的 Integer 对象;
- IntegerCache 实际上就是 Integer 的一个工厂类虽然没有以 Factory 结尾。
- IntegerCache 中缓存了 -128~127 的 Integer 对象,如果调用 Integer.value 的 int 值在其范围内,则会直接从 Cache 中返回。
- Integer 对象和其他基本类型的包装对象都是不可变的对象。
为什么默认是 -128~127 这个范围可调吗?
- 因为预先创建过多的对象,会占用内存并且导致加载时间延长所以只能在一定范围内缓存 所以缓存了 1 个字节大小的整形值。
- 可以调
-Djava.lang.Integer.Cache.high=255 或者 -XX:AutoBoxCacheMax=255
Long、Short、Byte 等基础类型的包装类型都有缓存对应范围的对象
享元模式在 String 中的应用
在 Java 中 有一个字符串常量池,在加载时一些字符串就会被创建到常量池中。后续引用到相同的字符串则可以从常量池中直接获取。这也是享元模式的一种应用。
对比
享元模式和单例模式的区别
- 单例模式中一个类只能创建一个对象,享元模式中是创建多个对象后被多处代码共享。
- 享元模式有点像单例模式的变体,多例模式,但是仍然有很大的区别。区别在和多例模式的设计意图上
- 多例模式单例模式都是意在控制对象的数量,而享元模式的意图是对象共享
享元模式与缓存的区别
- 享元模式通过工厂来“缓存”创建好的对象,但是这里的缓存更多的意思是存储。
- 缓存系统是为了提高访问效率而存在的,而享元模式只是为了复用。
总结
应用享元模式前应该仔细测试是否真的在业务场景中能节省大量内存,否则可能适得其反。
优点
- 享元模式在对象被密集使用,并且内容不变时能在多处共享节省大量内存
缺点
- 对垃圾回收不友好,因为共享的对象一保有引用不会释放。
- 如果对象的生命周期很短并且不会被密集使用,使用享元模式可能占用更多的内存。
相关文章:
【设计模式】结构型设计模式之 享元模式
文章目录 介绍关键概念 应用举例象棋游戏共享棋子对象文本编辑器中文字格式设计成享元模式 享元模式在 Java 中的应用享元模式在包装类缓存中的应用享元模式在 String 中的应用 对比享元模式和单例模式的区别享元模式与缓存的区别 总结优点缺点 介绍 享元模式,”享…...
嵌入式操作系统_5.存储管理
1.存储管理 存储管理是嵌入式操作系统的基本功能之一。其管理的对象是主存,也称内存。它的主要功能包括分配和回收主存空间、提高主存利用率、扩充主存、对主存信息实现有效保护。存储器管理的目的就是提供一个有价值的内存抽象,其目标包括:…...
HTML DOM 事件
HTML DOM 事件 HTML DOM(文档对象模型)事件是当网页中的某些操作发生时,浏览器会自动触发或通过脚本代码手动触发的动作。这些事件可以是对用户操作的响应,如点击按钮,也可以是浏览器自身的动作,如页面加载完成。理解和掌握DOM事件对于前端开发至关重要,因为它们是实现…...
有没有硅基生命?AGI在哪里?
摘要 随着科技的飞速发展,人工智能(AI)和生命科学的探索逐渐成为人们关注的焦点。其中,关于硅基生命的可能性与AGI(Artificial General Intelligence,即人工通用智能)的实现,更是引…...
HAL库开发--串口
知不足而奋进 望远山而前行 目录 文章目录 前言 学习目标 学习内容 开发流程 串口功能配置 串口功能开启 串口中断配置 串口参数配置 查询配置结果 发送功能测试 中断接收功能测试 printf配置 DMA收发 配置 DMA发送 DMA接收(方式1) DMA接收(方式2) 总结 前言…...
Web前端设计毕业论文:深度探索与未来展望
Web前端设计毕业论文:深度探索与未来展望 在数字化时代,Web前端设计作为互联网应用的重要组成部分,其重要性和复杂性日益凸显。本论文旨在深度探索Web前端设计的关键要素、发展趋势以及面临的挑战,为未来的研究和实践提供有价值的…...
JAVA 字节运算 取低5位 获取低位第一位
1、JAVA 取低5位 什么是取低5位 在计算机中,每个数字都是以二进制形式存储的。一个二进制数字可以由多个位组成,每一位都可以是 0 或者 1。取低5位即表示只取二进制数字的最后5位(从右向左数)。 取低5位的方法 在 JAVA 中&#…...
全网首发:教你如何直接用4090玩转最新开源的stablediffusion3.0
1.stablediffusion的概述: Stable Diffusion(简称SD)近期的动态确实不多,但最新的发展无疑令人瞩目。StableCascade、Playground V2.5和Stableforge虽然带来了一些更新,但它们在SD3面前似乎略显黯然。就在昨晚&#x…...
智慧监狱技术解决方案
1. **建设背景**:介绍了智慧监狱建设的战略部署,包括司法部提出的“数字法治、智慧司法”信息化体系建设,以及智慧监狱建设的总体目标、重点任务和实施步骤。 2. **建设需求**:分析了当前监狱系统存在的问题,如子系统…...
QT——事件
一、什么是事件 在QT中,事件(Event)是指由特定对象发生的动作或状态变化,通常用于响应用户的操作。事件可以是鼠标点击、键盘输入、窗口移动等用户操作,也可以是系统发出的信号,比如定时器超时、网络数据到达等。在QT中,可以通过连接信号与槽(Signals and Slots)的方…...
【SpringBoot】Spring Boot 中高级特性详解
文章目录 1. 异步处理1.1 什么是异步处理?1.2 实现异步处理1.2.1 启用异步支持1.2.2 使用 Async 注解1.2.3 调用异步方法 2. 安全管理2.1 Spring Security 集成2.2 基础安全配置2.2.1 添加依赖2.2.2 默认配置2.2.3 自定义用户认证 3. 监控和调试3.1 Spring Boot Act…...
MQTT TCP HTTP 协议对比
目录 1. 类型与用途 2. 通信模式与特性 3. 优缺点 4. 使用场景 MQTT、TCP和HTTP在类型、用途、通信模式、特性以及使用场景等方面存在显著的区别,以下是详细的阐述: 1. 类型与用途 MQTT:MQTT是一种消息传输协议,主要适用于物…...
C++面向对象程序设计 - 函数库
C语言程序中各种功能基本上都是由函数来实现的,在C语言的发展过程中建立了功能丰富的函数库,C从C语言继承了些函数功能。如果要用函数库中的函数,就必须在程序文件中包含文件中有关的头文件,在不同的头文件中,包含了不…...
computeIfAbsent是Java 8引入的Map接口中的一个方法
computeIfAbsent是Java 8引入的Map接口中的一个方法,它提供了一种更高效且线程安全的方式来 conditionally compute or retrieve a value for a given key in a map. 当你想要为一个键计算一个值(如果该键尚不存在对应的映射关系),…...
HTML实现进度条/加载框模版
HTML加载 一、环形加载 1二、环形加载 2三、波形加载四、百分比环形五、进度条 一、环形加载 1 <div class"loader"></div>.loader {border: 16px solid #f3f3f3;border-radius: 50%;border-top: 16px solid #3498db;width: 120px;height: 120px;-webki…...
Python 3 列表
Python 3 列表 Python 3 中的列表是一种基本的数据结构,用于存储一系列有序的元素。列表是可变的,这意味着可以修改其内容。在 Python 中,列表是非常灵活和强大的,广泛用于各种编程任务。 创建列表 创建列表非常简单,只需将元素用逗号分隔,并包围在方括号 [] 内。例如…...
Type-C接口显示器:C口高效连接与无限可能 LDR
Type-C显示器C接口的未来:高效连接与无限可能 随着科技的飞速发展,我们的日常生活和工作中对于高效、便捷的连接方式的需求日益增加。在这样的背景下,Type-C接口显示器凭借其卓越的性能和广泛的兼容性,正逐渐崭露头角,…...
微服务SpringCloud ES分布式全文搜索引擎简介 下载安装及简单操作入门
Elasticsearch ES简介 分布式全文搜索引擎 我们天天在用ES 搜索的时候 要与多个信息进行匹配查找 然后返回给用户 首先 ES会将数据库中的信息 先进行一个拆分 这个叫做分词 是按照词语关键词拆的 然后就能进行搜索的时候匹配对应的id 每一个关键字对应若干id 每一个…...
护眼灯落地的好还是桌面的好?落地护眼灯性价比高的品牌推荐
护眼灯落地的好还是桌面的好?当我们为了更好地保护眼睛而选择护眼灯时,常常会面临一个纠结的问题:到底是护眼灯落地的好还是桌面的好呢?这看似是一个简单的二选一,实则背后蕴含着诸多需要深入探讨的因素。 护眼灯的选择…...
计算机网络-子网掩码的计算
计算机网络中的子网掩码计算及相关知识 在计算机网络中,子网掩码是一个非常重要的概念。它不仅帮助我们区分网络地址和主机地址,还在网络划分、管理和安全中发挥着重要作用。本文将介绍子网掩码的基本概念、计算方法及其在网络中的应用。 子网掩码的基…...
Java:111-SpringMVC的底层原理(中篇)
这里续写上一章博客(110章博客): 现在我们来学习一下高级的技术,前面的mvc知识,我们基本可以在67章博客及其后面相关的博客可以学习到,现在开始学习精髓: Spring MVC 高级技术: …...
Vue3新特性指南:探索新增指令、内置组件和改进
Vue.js是一款流行的JavaScript框架,用于构建现代Web应用。Vue3是Vue.js的最新版本,引入了许多新特性和改进。本文将介绍Vue3新增的指令、内置组件以及其他值得关注的改进,并提供使用组合式API的用法示例。 一、新增指令 v-is指令: v-is指令用于动态组件,可以根据表达式的值来…...
Qt项目天气预报(2) - 重写事件函数
鼠标右键实现退出界面 知识点QMenu: QMenu 弹出对话框 --> 相对QMessageBox 更加轻量点 QMenu是Qt库中用于创建弹出式菜单的类,它通常出现在应用程序的顶部菜单栏、按钮的右键菜单或自定义上下文菜单中。以下是关于QMenu的详细介绍: 1. 类的基本特…...
uni-app前端,社区团购系统搭建部署
目录 前言: 一、社区团购模式: 二、社区团购系统功能: 三、总结: 前言: 区团购系统是一种利用互联网技术和组织力量,通过线上线下结合的方式,为社区居民提供方便快捷的商品和服务采购平台。…...
基于iBeacon蓝牙定位技术的反向寻车系统
随着城市化进程的加速和汽车保有量的不断增加,大型停车场成为了人们日常生活中不可或缺的一部分。然而,在繁忙的停车场中快速找到自己的车辆,成为了许多车主的难题。为了解决这一问题,维小帮基于iBeacon蓝牙技术打造的反向寻车系统…...
CCAA质量管理【学习笔记】 备考知识点笔记(五)质量设计方法与工具
第五节 质量设计方法与工具 1 任 务 分 解 法 1.1 概念 任务分解法,又称工作分解结构 (Work Breakdown Structure, 简 称 WBS) 。WBS 指以可交付成果为 导向,对项目团队为实现项目目标并完成规定的可交付成果而执行的工作所进行的层次分解。W…...
RIP路由协议汇总(华为)
#交换设备 RIP路由协议汇总 一、原理概述 当网络中路由器的路由条目非常多时,可以通过路由汇总(又称路由汇聚或路由聚合)来减少路由条目数,加快路由收敛时间和增强网络稳定性。路由汇总的原理是,同一个自然网段内的不…...
服务部署:.NET项目使用Docker构建镜像与部署
前提条件 安装Docker:确保你的Linux系统上已经安装了Docker。如果没有,请参考官方文档进行安装。 步骤一:准备项目文件 将你的.NET项目从Windows系统复制到Linux系统。你可以使用Git、SCP等工具来完成这个操作。如何是使用virtualbox虚拟电…...
力扣1170.比较字符串最小字母出现频次
力扣1170.比较字符串最小字母出现频次 f()是找最小字母的次数 即cnt中第一个出现过的字母 将word中所有字符串都处理存入nums nums排序 再做二分 class Solution {public:int f(string s){int cnt[26] {0};for(char c:s)cnt[c - a] ;for(int i0;i<26;i) cout<<cn…...
boost asio异步服务器(3)增加发送队列实现全双工通信
增加发送节点 构造发送节点,管理发送数据。发送节点的类如下。 这个发送节点用于保证发送和接收数据的有效性。 增加发送队列 前边实现的是一个简单的echo服务器,也就是服务器将收到的内容发送给对应的客户端。但是在实际的服务器设计中,服务…...
手机网站怎么备案/网络营销的特点有哪些特点
用Toast来作为操作成功以及用户误操作等等的提示,非常的简单。直接上代码: 创建方式一: ps: 此处没有设置toast的其他属性,均使用默认的风格(个人觉得默认的风格除了字体比较小之外 还是挺好看的࿰…...
门户网站建设摘要/seo外链专员工作要求
变量使用前使用后都要dispose!1、变量用完之后,Dispose()和置Null。C#会把hobject当成一个小内存占用对象,我的猜测是halcon对hobject中只是包装了一个指针,然后C#语言无法将其识别为像bitmap那样的对象,所以只要有hob…...
深圳腾网站建设/厦门seo排名外包
在向服务器添加SCSI硬盘时,可以在服务器不停机的情况下,让系统识别出新插入的硬盘,具体步骤如下:第一步:将新硬盘插到机器上;第二步:以root用户运行命令:echo "scsi add-single-device x y…...
yyf做的搞笑视频网站/网络营销策略分析
Apache与nginx的对比 Apache:select模型(类似于同步)高并发的时候占用资源较多。 Nginx:epoll模型()类似于异步),对小文件并发有很大优势,大文件并发上一般,…...
免费个人二级域名网站/品牌策划方案怎么做
2021.11.23下午学习笔记 在流程图中,长方形表示判断模块,椭圆形表示中止模块。 从判断模块引出的左右箭头称为分支。 决策树的主要优势在于数据形式非常容易理解。 机器根据数据集创建规则的过程就是机器学习的过程。 3.1 决策树的构造 优缺点&#…...
网站开发职责/网站批量查询工具
http://acm.hdu.edu.cn/showproblem.php?pid4849 会有非常多奇怪的Wa的题。当初在西安就不知道为什么wa,昨晚做了,由于一些Sb错误也wa了非常久。这会儿怎么写都会AC。。。。 收获: 1、还是基本都构思好在去写程序,由于当时没过。…...