享元模式的理解和实践
在软件开发中,性能优化是一个永恒的话题。在追求高性能的过程中,减少内存的使用是一项重要的任务。享元模式(Flyweight Pattern)就是一种用于减少内存使用量的设计模式,它特别适用于存在大量重复对象的场景。本文将详细介绍享元模式的概念、原理、优点和缺点,并通过Java代码示例展示其实际应用。

一、享元模式的概念
享元模式是一种结构型设计模式,它通过共享对象来减少内存的使用。享元(Flyweight)指的是可以共享的对象,这些对象具有内部状态(Intrinsic State)和外部状态(Extrinsic State)之分。内部状态是存储在享元对象内部的状态,可以在多个客户端之间共享;外部状态是由客户端保存的状态,它在享元对象被使用时被传入。
享元模式的核心思想是:通过共享已经存在的对象,而不是每次需要时都创建新的对象,从而减少内存的使用。享元模式通常与工厂模式结合使用,通过一个工厂类来管理享元对象的创建和共享。
二、享元模式的原理
享元模式的原理可以用以下步骤来概括:
- 定义享元接口:定义一个接口,用于声明享元对象的方法。
- 实现具体享元类:实现享元接口,并包含内部状态。如果需要,也可以包含一个方法用于设置外部状态。
- 创建享元工厂类:工厂类用于创建和管理享元对象。它维护一个存储享元对象的池(Pool),并根据请求返回相应的享元对象。
- 客户端代码:客户端代码通过享元工厂获取享元对象,并设置外部状态,然后调用享元对象的方法。
三、享元模式的优点和缺点
优点:
- 减少内存使用:通过共享对象,显著减少了内存的使用量。
- 提高性能:减少了对象的创建和销毁,提高了系统的性能。
- 易于管理:享元工厂类集中管理享元对象,方便进行管理和维护。
缺点:
- 增加了系统的复杂性:需要区分内部状态和外部状态,增加了代码的复杂性。
- 不适用于所有场景:只有在存在大量重复对象的场景下,享元模式才能发挥其优势。如果对象数量不多,反而会增加系统的开销。
四、享元模式的Java实现
下面通过一个具体的例子来展示享元模式的实现。假设我们有一个表示字符的类,每个字符对象都有一个唯一的字符标识(内部状态)和一个显示位置(外部状态)。我们可以使用享元模式来共享这些字符对象。
定义享元接口:
public interface Flyweight {void display(String extrinsicState);
}
实现具体享元类:
import java.util.HashMap;
import java.util.Map;public class CharacterFlyweight implements Flyweight {private final char intrinsicState;private static final Map<Character, CharacterFlyweight> pool = new HashMap<>();// 私有构造函数,通过工厂方法创建对象private CharacterFlyweight(char intrinsicState) {this.intrinsicState = intrinsicState;}// 工厂方法,用于获取享元对象public static CharacterFlyweight getInstance(char intrinsicState) {CharacterFlyweight flyweight = pool.get(intrinsicState);if (flyweight == null) {flyweight = new CharacterFlyweight(intrinsicState);pool.put(intrinsicState, flyweight);}return flyweight;}@Overridepublic void display(String extrinsicState) {System.out.println("Character: " + intrinsicState + " at position: " + extrinsicState);}
}
客户端代码:
public class FlyweightPatternDemo {public static void main(String[] args) {// 获取享元对象并设置外部状态Flyweight flyweight1 = CharacterFlyweight.getInstance('A');flyweight1.display("Top-Left");Flyweight flyweight2 = CharacterFlyweight.getInstance('B');flyweight2.display("Top-Right");// 获取相同的享元对象,并设置不同的外部状态Flyweight flyweight3 = CharacterFlyweight.getInstance('A');flyweight3.display("Bottom-Left");// 验证是否为同一个对象System.out.println(flyweight1 == flyweight3); // 输出: true}
}
在这个例子中,CharacterFlyweight类实现了Flyweight接口,并通过一个静态的pool来存储已经创建的享元对象。getInstance方法用于获取享元对象,如果对象已经存在,则直接返回;如果不存在,则创建新的对象并放入池中。客户端代码通过调用getInstance方法获取享元对象,并设置外部状态,然后调用display方法显示字符和位置信息。
运行上述代码,输出如下:
Character: A at position: Top-Left
Character: B at position: Top-Right
Character: A at position: Bottom-Left
true
可以看到,字符'A'的享元对象是共享的,flyweight1和flyweight3实际上是同一个对象。
总结
享元模式是一种用于减少内存使用量的设计模式,它通过共享对象来减少内存的使用。享元模式适用于存在大量重复对象的场景,通过区分内部状态和外部状态,实现对象的共享。虽然享元模式增加了系统的复杂性,但在合适的场景下,它能够显著提高系统的性能和减少内存的使用。通过Java代码示例,我们展示了享元模式的实现和应用,希望能够帮助读者更好地理解和实践这一设计模式。
相关文章:
享元模式的理解和实践
在软件开发中,性能优化是一个永恒的话题。在追求高性能的过程中,减少内存的使用是一项重要的任务。享元模式(Flyweight Pattern)就是一种用于减少内存使用量的设计模式,它特别适用于存在大量重复对象的场景。本文将详细…...
Unreal Engine 中的UI界面开发
推荐的使用方式 轻量级 HUD:使用 Canvas 绘制简单的文本、调试信息或基础 UI(如准星、血量条等)。 复杂 UI:使用 UMG(Unreal Motion Graphics)和 Slate 进行布局和交互,避免手动管理 Canvas 绘制。 避免遮挡场景:仅绘制必要的内容,并利用透明度(如 FLinearColor(1, 1…...
Docker在Ubuntu和CentOS系统下的安装
目录 1. 各版本平台支持情况2. 在Ubuntu系统下安装docker3. 常见报错4. Docker的镜像源修改5. Docker目录修改6. 在CentOS系统下安装docker 1. 各版本平台支持情况 (1)平台支持情况如下: Server 版本 桌面版本 2. 在Ubuntu系统下安装docker…...
EXCEL 关于plot 折线图--频度折线图的一些细节
目录 0 折线图有很多 1 频度折线图 1.1 直接用原始数据做的频度折线图 2 将原始数据生成数据透视表 3 这样可以做出了,频度plot 4 做按某字段汇总,成为累计plot分布 5 修改上面显示效果,做成百分比累计plot频度分布 0 折线图有很多 这…...
Hive操作案例
目录 idea/dg远程连接导入数据建表数据导入 idea/dg远程连接 hive的详细安装不多展示,自行搜索即可。 依次启动zookeeper,hadoop 在zookeeper的节点上启动如下指令(我的是1个主节点和2个备用节点) 启动Hive的metastore࿰…...
C++ 内存管理和模板与STL
此篇目是之后各种C库的基础 目录 内存管理 内存分布 内存管理方式 new和delete operator new 与 operator delete函数 实现原理 定位new表达式(placement-new) 模板基础 泛型编程 模板 函数模板 类模板 STL 组成部分 内存管理 内存分布 int globalVar 1; //全局变量 静…...
JDK8新特性:Stream
JDK8最大的改变: 1. lambda表达式 2. Stream 1. Steam流的入门 什么是Stream? 也叫Stream流,是jdk8开始的一套API,用于操作集合或者数组中的数据 优点: Stream流大量结合了Lambda的语法风格来创建,提…...
前端传入Grule,后端保存到 .grl 文件中
前端传入Grule,后端保存到 .grl 文件中 通过简单的输入框,将Grule的部分拆解成 规则名称 规则描述 规则优先级 规则条件 规则逻辑Grule关键字 when Then 模拟了 if 判断的条件和逻辑部分 类似于 shell 和 ruby 之类的脚本语言,有 then 关键字…...
探索《Crypto Rumble》 游戏:经济模型篇
《Crypto Rumble》是一款基于 Zypher Network 游戏引擎打造的卡牌 RPG三消品类的 Web3 游戏,通过引人入胜的游戏设计以及轻量化的游戏玩法,《Crypto Rumble》不仅能够为玩家带来引人入胜的沉浸式游戏体验,同时基于 AI Bot 的游戏编辑器&#…...
【CSS in Depth 2 精译_072】第 12 章 CSS 排版与间距概述 + 12.1 间距设置(上):究竟该用 em 还是 px
当前内容所在位置(可进入专栏查看其他译好的章节内容) 第四部分 视觉增强技术 ✔️【第 12 章 CSS 排版与间距】 ✔️ 12.1 间距设置 ✔️ 12.1.1 使用 em 还是 px ✔️12.1.2 对行高的深入思考12.1.3 行内元素的间距设置 文章目录 第 12 章 排版与间距…...
Elasticsearch对象映射
Spring Data Elasticsearch对象映射是将Java对象(域实体)映射到存储在Elasticsearchs中的JSON表示形式并返回的过程。内部用于此映射的类是MappingElasticsearchConverter。 元模型对象映射 基于元模型的方法使用域类型信息对Elasticsearch进行读写操作…...
Oracle 19c rac 补丁升级,从19.7 to19.22-集群
1. 补丁包概述 数据库环境 角色 数据库 IP地址 数据库版本 主机名 数据库名称 源端 RAC 172.30.21.166/167 19.7 hfcwdb66/hfcwdb67 hfdb 将以下补丁包上传到/soft下 上传到两个节点的soft目录下:p6880880_190000_Linux-x86-64.zip (更新o…...
机器学习--Kaggle的使用
机器学习–Kaggle的使用 打开Kaggle: Your Machine Learning and Data Science Community并点击Sign In登录账号 kaggle中自带了很多的数据集 在点击Datasets之后,单点Notebook,如果有适用的数据集可以单击Copy and Edit复制其Notebook,之后…...
客户服务新突破,天润融通助力电动车企业实现数智化转型
近年来,两轮电动车成为年轻人喜爱的出行新方式,借着这种潮流,许多新兴品牌迅速发展,并跻身行业头部。 但问题也随之而来,由于业务快速发展,各类服务问题也开始增多。 比如天润融通服务的一家头部两轮电动…...
力扣题目 - 2931.购买物品的最大开销
题目 还需要你前往力扣官网查看详细的题目要求 地址 思路 这边需要你去力扣官网详细查看题目看了题目提供的示例 已经有了解法, 先把values转成1维数组,排序之后进行累加即可 代码 var maxSpending function (values) {let list values.flat();list.sort((a, b) > a - …...
智慧化工园区自动化在线监测,建立产业链路数字安全网
智慧化工升级国家政策推动安全风险频发 化工园区作为化工产业的核心集聚地,在全球经济中占据重要地位。为推动行业的高质量发展,国家相继发布了《“十四五”危险化学品安全生产规划方案》、《石化化工行业数字化转型实施指南》和《化工园区安全风险智能化…...
在Docker中运行MySQL的思考:挑战与解决方案
引言 在云计算和容器化技术日益普及的今天,Docker作为一种轻量级的容器化平台,已经成为开发和部署应用的首选工具之一。其提供的便携性、可扩展性和环境一致性对于无状态微服务来说无疑是巨大的福音。然而,并非所有应用都适合在Docker容器中…...
Linux中所有和$有关的操作
prog < file 命令在 Shell 编程中用于 输入重定向,它将文件的内容作为程序的输入。即,程序 prog 会从文件 file 中读取数据,而不是从标准输入(通常是键盘)读取数据。 基本语法: prog < file 解释&…...
github操作学习笔记(杂乱版)
git开源的分布式版本控制系统: 每次修改文件提交后,都会自动创建一个项目版本 查看git版本看有没有安装成功:git --version 把默认编辑器设置成vim:git config --global core.editor "vim" 1、设置昵称和邮箱ÿ…...
学习思考:一日三问(思考篇)之路由表
学习思考:一日三问(思考篇)之路由表 学了什么(是什么)Destination/Mask(最终目标,寻路必须)Proto(择优可选)Pre(择优可选)Cost&#x…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
