java设计模式八 享元
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术有效地支持大量细粒度的对象。这种模式通过存储对象的外部状态在外部,而将不经常变化的内部状态(称为享元)存储在内部,以此来减少内存中对象的数量。享元模式适用于那些可以共享的对象,以此来减少系统创建对象的数量,从而提升效率和性能。
### 案例分析:文字处理软件中的字符渲染
假设我们正在开发一个文字处理软件,需要显示大量的字符。每个字符可能有不同的颜色、字体和大小等属性,但字符本身(如'a', 'b', 'c'等)却是有限的。如果不使用享元模式,我们会为每个带有独特属性组合的字符创建一个对象,这会导致内存中存在大量重复的字符对象。
#### 享元模式的应用步骤:
1. **定义享元接口**:
定义一个接口或抽象类,声明一个或多个方法用于操作内部状态,通常还会有一个方法来获取外部状态。
```java
public interface Character {void display(char character, Color color, Font font);
}
```
2. **实现享元类**:
实现享元接口,并存储内部状态(在这个案例中,内部状态为空,因为字符是固定的)。
```java
public class ConcreteCharacter implements Character {@Overridepublic void display(char character, Color color, Font font) {System.out.printf("Rendering character '%c' with color %s and font %s%n", character, color, font);}
}
```
3. **创建享元工厂**:
工厂负责创建和管理享元对象,确保相同的字符复用同一个对象。为了高效地查找享元,通常会使用如HashMap这样的数据结构来存储已经创建的享元对象。```java
public class CharacterFactory {private Map<Character, ConcreteCharacter> pool = new HashMap<>();public Character getCharacter(char character) {ConcreteCharacter flyweight = pool.get(character);if (flyweight == null) {flyweight = new ConcreteCharacter();pool.put(character, flyweight);}return flyweight;}
}
```
4. **客户端代码**:
客户端从享元工厂获取享元对象,并设置外部状态(颜色、字体)后调用其方法。
```java
public class TextEditor {private CharacterFactory factory;public TextEditor() {factory = new CharacterFactory();}public void renderText(String text, Color color, Font font) {for (char c : text.toCharArray()) {Character character = factory.getCharacter(c);character.display(c, color, font);}}
}// 使用示例
TextEditor editor = new TextEditor();
editor.renderText("Hello, World!", Color.RED, Font.TIMES_ROMAN);
```
在这个例子中,尽管每个字符在屏幕上显示时可能有不同的颜色和字体,但字符本身是有限的。享元模式通过`CharacterFactory`确保了对于每个不同的字符仅创建一个`ConcreteCharacter`实例,并通过传递外部状态(颜色和字体)来展示字符的不同表现,从而极大地减少了内存占用。
继续深入,我们可以探讨享元模式的一些关键优势、应用场景及注意事项,以加深对这一设计模式的理解。
### 关键优势
1. **内存优化**:最显著的优势是大幅度减少内存中对象的数量,特别是当存在大量相似对象时。这在处理大数据量或图形密集型应用时尤为重要,能有效减少内存占用,提高系统性能。
2. **性能提升**:减少了对象的创建和销毁过程,降低了垃圾回收的压力,提升了系统的运行速度。
3. **易于维护和扩展**:通过集中管理享元对象,使得对内部状态的修改变得更加集中和容易控制。同时,新的享元类型可以轻松添加到系统中,不影响现有代码。
### 应用场景
- **图形处理**:如上述字符渲染例子,图像处理软件中的像素、图标库等。
- **大量相似对象**:游戏开发中的子弹、棋盘上的棋子等,这些对象除了位置等少数状态外,其他大部分属性都相同。
- **字符串处理**:文本编辑器中的字符或单词,特别是在实现复杂格式化时。
- **网络编程**:连接池的设计中,复用数据库连接或socket连接等资源。
### 注意事项
1. **区分内外部状态**:正确区分对象的内部状态(被享元对象管理,不随环境改变)和外部状态(由客户端控制,随环境改变)。错误地处理状态可能会导致逻辑错误或数据混乱。
2. **线程安全**:当享元对象在多线程环境下被共享时,需要考虑线程安全问题。可能需要在享元类中加入同步机制或确保外部状态的线程安全性。
3. **初始化成本**:虽然享元模式能减少运行时的内存消耗,但如果享元对象的创建成本很高,初始化大量享元可能会影响程序的启动时间。
4. **过度设计**:在对象数量不是特别庞大,或者内存不是主要瓶颈的情况下,过度使用享元模式可能会增加系统的复杂度,得不偿失。因此,是否采用享元模式需根据实际情况权衡。
通过合理运用享元模式,可以在保证程序高效、内存友好的同时,保持代码的清晰与可维护性,是面向对象设计中一项非常实用的技巧。
接下来,让我们进一步探索享元模式在实际开发中的一些高级应用技巧和设计考量,以及如何与其他设计模式结合使用,以达到更好的效果。
### 高级应用技巧
1. **使用复合享元**:当享元对象需要组合其他享元对象以形成更复杂的结构时,可以引入复合享元的概念。例如,在游戏开发中,一个复合角色可能包含武器、防具等多个独立的享元对象,通过组合这些享元来构建更丰富的实体。
2. **懒加载**:为了进一步优化内存使用,可以在享元工厂中实现享元对象的懒加载策略。即首次请求某个享元时才创建它,而不是一开始就创建所有可能用到的享元对象。
3. **缓存管理**:对于内存敏感的应用,可以实施更精细的缓存管理策略,比如设置缓存上限,当缓存超出限制时,根据某种策略(如最近最少使用LRU)移除部分享元对象。
### 与其他设计模式结合
1. **与工厂模式结合**:如之前提到的,享元工厂负责创建和管理享元对象,这是工厂模式的一个典型应用。结合工厂模式,可以更加灵活和高效地控制享元对象的生命周期和分配。
2. **与代理模式结合**:当需要为享元对象添加额外的操作或控制访问时,可以通过代理模式包装享元对象。代理可以处理外部状态的传递,以及任何与具体业务逻辑相关的操作,同时保持享元对象本身的纯粹性。
3. **与状态模式结合**:如果享元对象的行为依赖于其状态,且这些状态变化较为复杂,可以引入状态模式来管理这些状态变化。享元对象的内部状态通过状态对象表示,状态对象的变化不会影响享元对象的身份,从而维持享元的共享特性。
### 总结
享元模式是一个强大的设计工具,它通过共享技术减少系统中对象的数量,优化了内存使用并提高了性能。在设计和实现时,需要细心区分内外部状态,考虑并发访问的线程安全问题,以及选择合适的时间和场景应用该模式。通过与其他设计模式的结合使用,可以解决更为复杂的问题,构建出更加高效、灵活的系统。掌握并灵活运用享元模式,是提升软件设计质量的重要一步。
相关文章:
java设计模式八 享元
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术有效地支持大量细粒度的对象。这种模式通过存储对象的外部状态在外部,而将不经常变化的内部状态(称为享元)存储在内部,以此来减…...
ELK原理详解
ELK原理详解 一、引言 在当今日益增长的数据量和复杂的系统环境中,日志数据的收集、存储、分析和可视化成为了企业运营和决策不可或缺的一部分。ELK(Elasticsearch、Logstash、Kibana)堆栈凭借其高效的性能、灵活的扩展性和强大的功能&…...

多线程学习Day09
10.Tomcat线程池 LimitLatch 用来限流,可以控制最大连接个数,类似 J.U.C 中的 Semaphore 后面再讲 Acceptor 只负责【接收新的 socket 连接】 Poller 只负责监听 socket channel 是否有【可读的 I/O 事件】 一旦可读,封装一个任务对象&#x…...
第33次CSP认证Q1:词频统计
🍄题目描述 在学习了文本处理后,小 P 对英语书中的 𝑛n 篇文章进行了初步整理。 具体来说,小 P 将所有的英文单词都转化为了整数编号。假设这 𝑛n 篇文章中共出现了 𝑚m 个不同的单词,则把它们…...

pytorch加载模型出现错误
大概的错误长下面这样: 问题出现的原因: 很明显,我就是犯了第一种错误。 网上的修改方法: 我觉得按道理哈,确实,蓝色部分应该是可以把问题解决了的。但是我没有解决,因为我犯了另外一个错…...

如何在Mac上恢复格式化硬盘的数据?
“嗨,我格式化了我的一个Mac硬盘,而没有使用Time Machine备份数据。这个硬盘被未知病毒感染了,所以我把它格式化为出厂设置。但是,我忘了备份我的文件。现在,我想恢复格式化的硬盘驱动器并恢复我的文档,您能…...

华为OD机试 - 手机App防沉迷系统(Java 2024 C卷 100分)
华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试…...

搜维尔科技:光学动作捕捉系统用于城市公共安全智慧感知实验室
用户名称:西安科技大学 主要产品:Optitrack Priime41 光学动作捕捉系统(8头) 在6米8米的空间内,通过8个Optitrack Priime41光学动作捕捉镜头,对人体动作进行捕捉,得到用户想要的人体三维空间坐…...

保研面试408复习 4——操作系统、计网
文章目录 1、操作系统一、文件系统中文件是如何组织的?二、文件的整体概述三、UNIX外存空闲空间管理 2、计算机网络一、CSMA/CD 协议(数据链路层协议)二、以太网MAC帧MTU 标记文字记忆,加粗文字注意,普通文字理解。 1、…...

实战攻防中关于文档的妙用
一、PPT钓鱼 简单制作一个用于钓鱼的PPTX文件 一般那种小白不知道PPT也能拿来钓鱼,这里主要是借用PPT中的”动作按钮”, 我们在插入的地方,选择“动作按钮” 然后在弹出的窗口处: 比如填入上线CS的语句:powershell.exe -nop -w …...

【使用ChatGPT的API之前】OpenAI API提供的可用模型
文章目录 一. ChatGPT基本概念二. OpenAI API提供的可用模型1. InstructGPT2. ChatGPT3. GPT-4 三. 在OpenAI Playground中使用GPT模型-ing 在使用GPT-4和ChatGPT的API集成到Python应用程序之前,我们先了解ChatGPT的基本概念,与OpenAI API提供的可用模型…...

【C语言】模拟实现深入了解:字符串函数
🔥引言 本篇将模拟实现字符串函数,通过底层了解更多相关细节 🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C笔记专栏: C笔记 🌈喜欢的诗句:无人扶我青云志 我自…...
钩子函数onMounted定义了太多访问MySQL的操作 导致数据库异常
先放几种后端遇到的异常,多数和数据库有关 pymysql.err.InternalError: Packet sequence number wrong - got 102 expected 1 127.0.0.1 - - [09/May/2024 17:49:37] "GET /monitorLastTenList HTTP/1.1" 500 AttributeError: NoneType object has no at…...

Excel文件解析---超大Excel文件读写
1.使用POI写入 当我们想在Excel文件中写入100w条数据时,使用XSSFWorkbook进行写入时会发现,只有将100w条数据全部加载到内存后才会用write()方法统一写入,效率很低,所以我们引入了SXXFWorkbook进行超大Excel文件读写。 通过设置 …...
TypeScript基础:类型系统介绍
TypeScript基础:类型系统介绍 引言 TypeScript,作为JavaScript的一个超集,引入了类型系统,这为开发大型应用程序带来了诸多好处。本文将介绍TypeScript类型系统的基础知识,帮助初学者理解其概念和用法。 基础知识 …...

【Unity】Unity项目转抖音小游戏(一) 项目转换
UnityWEBGL转抖音小游戏流程 业务需求,开始接触一下抖音小游戏相关的内容,开发过程中记录一下流程。 相关参考: 抖音文档:https://developer.open-douyin.com/docs/resource/zh-CN/mini-game/develop/guide/game-engine/rd-to-SC…...
element-ui 中修改loading加载样式
element-ui 中的 loading 加载功能,默认是全屏加载效果 设置局部,需要自定义样式或者修改样式,方法如下: import { Loading } from element-uiVue.prototype.$baseLoading (text) > {let loadingloading Loading.service({…...
QT登录界面,(页面的切换)
以登陆界面为例,(QDialog) 1.主界面先构造login 的对话框类 int main(int argc, char *argv[]) {QApplication a(argc, argv);//先显示Login的界面Study_Login_Dialog login;............ }2.Login的类,可以用自定义的信号&#…...

计算机毕业设计 | vue+springboot汽车销售管理系统(附源码)
1,项目介绍 本项目基于spring boot以及Vue开发,前端实现基于PanJiaChen所提供的开源后台项目vue-element-admin改造。 针对汽车销售提供客户信息、车辆信息、订单信息、销售人员管理、财务报表等功能,提供经理和销售两种角色进行管理。 2&…...

一款开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验
Snap.Hutao 胡桃工具箱是一款以 MIT 协议开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新功能相结合,提供了一套完整且实用的工具集,且无需依赖任何移动设…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...

【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...