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 {
    @Override
    public 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. **与状态模式结合**:如果享元对象的行为依赖于其状态,且这些状态变化较为复杂,可以引入状态模式来管理这些状态变化。享元对象的内部状态通过状态对象表示,状态对象的变化不会影响享元对象的身份,从而维持享元的共享特性。

### 总结

享元模式是一个强大的设计工具,它通过共享技术减少系统中对象的数量,优化了内存使用并提高了性能。在设计和实现时,需要细心区分内外部状态,考虑并发访问的线程安全问题,以及选择合适的时间和场景应用该模式。通过与其他设计模式的结合使用,可以解决更为复杂的问题,构建出更加高效、灵活的系统。掌握并灵活运用享元模式,是提升软件设计质量的重要一步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/9218.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ORA-02020:过多的数据库链接在使用

一、问题描述 今天同事说&#xff0c;有一个查询功能&#xff0c;同时查了几个子平台的dblink&#xff0c;页面返回报错。 提示ORA-02020&#xff1a;过多的数据库链接在使用&#xff1b; bad SQL grammar 二、解决办法 1&#xff09;分析业务需求 分析业务场景 &#xff0c;发…

美食推荐网站设计

**中文摘要&#xff1a;**在当今信息化、网络化的时代背景下&#xff0c;美食文化正逐渐融入人们的日常生活&#xff0c;而网络平台成为人们获取美食信息、分享美食体验的重要途径。为了满足广大美食爱好者对美食信息的探索和推荐需求&#xff0c;本文提出了一种创新的美食推荐…

谷歌开源!用 js 编写 Shell 脚本! | 开源日报 No.247

google/zx Stars: 41.4k License: Apache-2.0 zx 是一个用于编写更好脚本的工具。 提供有用的包装器&#xff0c;简化了对 child_process 的操作转义参数并提供合理的默认值使用 JavaScript 编写复杂脚本时比 Bash 更方便可以直接使用 npm 安装 dani-garcia/vaultwarden St…

Nest 快速上手 —— (三)中间件 / 异常过滤器

一、 中间件&#xff08;Middleware&#xff09; 1.特点 中间件是一个在路由处理程序之前被调用的函数。中间件函数可以访问请求和响应对象&#xff0c;以及应用程序请求-响应周期中的next()中间件函数。下一个中间件函数通常由一个名为next的变量表示。 中间件函数可以执行以…

5.9gunplot绘图堆叠柱状图

gunplot绘图堆叠柱状图 plot"要用的数据&#xff08;后缀名是.dat)" using 2 t(或者title) 跟着是要命名的属性名称 这个名称可以用.dat里的每列列名&#xff0c;也可以直接在后面跟着定义 plot "data.dat" using 2 t columnheader(2), using 3 t column…

PyQt5 解决界面无响应方案

文章目录 前言版本案例解决方案QThreadQTimer 局部变量创建异步线程导致 UI 未响应如果 QTimer 不使用 self.time 写法 个人简介 前言 在PyQt5中&#xff0c;GUI线程通常指的是Qt的主事件循环线程&#xff0c;也称为主线程。主线程负责处理GUI事件、更新UI界面等任务。在PyQt5…

vue的组件库

作为一个Vue.js开发者&#xff0c;使用组件库是提高效率和代码重用的关键。Vue的组件库为开发者提供了一系列预先构建好的组件&#xff0c;可以在项目中直接引用和定制。以下是一些关于Vue组件库的知识点和用法&#xff1a; 常见的Vue组件库&#xff1a; Element UI&#xff…

如何通过OMS加快大表迁移至OceanBase

OMS&#xff0c;是OceanBase官方推出的数据迁移工具&#xff0c;能够满足众多数据迁移场景的需求&#xff0c;现已成为众多用户进行数据迁移同步的重要工具。OMS不仅支持多种数据源&#xff0c;还具备全量迁移、增量同步、数据校验等功能&#xff0c;并能够对分表进行聚合操作&…

系统运维(虚拟化)

1.VLAN VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网&#xff0c;是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。 每个VLAN是一个广播域&#xff0c;VLAN内的主机间可以直接通信&#xff0c;而VLAN间则不能直接互通。这样&#xff0c;广播报…

深度学习网络:设计、开发和部署

​书籍&#xff1a;Deep Learning Networks: Design, Development and Deployment 作者&#xff1a;Jayakumar Singaram&#xff0c;S. S. Iyengar&#xff0c;Azad M. Madni 出版&#xff1a;Springer书籍下载-《​深度学习网络&#xff1a;设计、开发和部署》该教材为学生和工…

vue使用screenfull实现全屏模式

vue实现全屏模式可以通过第三方依赖screenfull完成效果。 实现效果&#xff1a;查看源码 首先需要安装第三方依赖 // npm npm install screenfull//yarn yarn add screenfull// pnpm pnpm install screenfull代码实现&#xff1a; <div class"flex-center w100 h…

986: 哈夫曼译码

解法&#xff1a;先把代码粘贴到编译器&#xff08;vs&#xff09;上&#xff0c;分享一个一键去除空白行的操作&#xff0c;ctrlf调出查找窗口&#xff0c;输入查找(?<\r\n)\r\n&#xff0c;选择正则表达式&#xff0c;替换就可以发现会去掉一百多行空白行。 本题只需要利…

业界首创!电子测量行业龙头推出PQC测试功能

是德科技公司宣布推出业界首创的测试功能&#xff0c;旨在测试后量子密码学(PQC)的稳健性。Keysight Inspector的最新功能是对综合平台的显着扩展&#xff0c;可帮助设备和芯片供应商识别和修复硬件漏洞。 量子计算旨在大幅加速复杂计算。这种发展将不可避免地威胁现有的加密技…

电商核心技术揭秘53:社群营销的策略与实施

相关系列文章 电商技术揭秘相关系列文章合集&#xff08;1&#xff09; 电商技术揭秘相关系列文章合集&#xff08;2&#xff09; 电商技术揭秘相关系列文章合集&#xff08;3&#xff09; 电商技术揭秘四十一&#xff1a;电商平台的营销系统浅析 电商技术揭秘四十二&#…

FinalShell连接虚拟机Linux系统连接超时

报错信息 java.net.ConnectException: Connection timed out: connect 排除是网络问题后可以尝试一下这个方法。 解决方案: 打开虚拟机终端输入:ifconfig 会出现端口信息: 看ens33这里的端口是多少&#xff0c;改一下重新连接就ok。

关于模型参数融合的思考

模型参数融合通常指的是在训练过程中或训练完成后将不同模型的参数以某种方式结合起来&#xff0c;以期望得到更好的性能。这种融合可以在不同的层面上进行&#xff0c;例如在神经网络的不同层之间&#xff0c;或者是在完全不同的模型之间。模型参数融合的目的是结合不同模型的…

为什么要计算光伏发电量等数据?

在当今世界&#xff0c;随着全球气候变化和环境问题的日益突出&#xff0c;可再生能源的利用和发展成为了全球关注的焦点。其中&#xff0c;光伏发电作为最具代表性的可再生能源之一&#xff0c;因其清洁、可再生的特性而备受瞩目。然而&#xff0c;光伏发电量的计算及其相关数…

数据挖掘(一)数据类型与统计

前言 打算新开一个笔记系列&#xff0c;基于国防科技大学 丁兆云老师的《数据挖掘》 数据挖掘 1、数据类型与统计 数据统计 最大值&#xff0c;最小值&#xff0c;平均值&#xff0c;中位数&#xff0c;位数&#xff0c;方差等统计指标 df.describe() #当调用df.describe(…

【OpenCV实战】基于OpenCV中DNN(深度神经网络)实现人体检测和使用穿越红线方式来统计人流量

一,思路逻辑和原理介绍 该过程主要基于计算机视觉和深度学习的原理。通过深度学习模型来自动识别和定位图像或视频帧中的人体,然后结合空间位置和时间信息来判断人体是否穿过红线。这种方法具有自动化、高效和准确的特点,可以广泛应用于各种需要监控和计数人流的场景中。 …

[uniapp 地图组件] 小坑:translateMarker的回调函数,会调用2次

大概率是因为旋转和移动是两个动画&#xff0c;动画结束后都会分别调用此函数 即使你配置了 【不旋转】它还是会调用两次&#xff0c; 所以此处应该是官方的bug