享元模式介绍

目录

一、享元模式介绍

1.1 享元模式定义

1.2 享元模式原理

1.2.1 享元模式类图

1.2.2 模式角色说明

1.2.3 示例代码

二、享元模式的应用

2.1 需求说明

2.2 需求实现

2.2.1 类图

2.2.2 具体实现

2.2.2.1 抽象享元类

2.2.2.2 共享享元类-白色棋子

2.2.2.3 共享享元类-黑色棋子

2.2.2.4 享元工厂类

2.2.2.5 测试类

三、享元模式总结

3.1 享元模式的优点

3.2 享元模式的缺点

3.3 享元模式的适用场景


一、享元模式介绍

1.1 享元模式定义

享元模式 (flyweight pattern) 的原始定义是:摒弃了在每个对象中保存所有数据的方式,通过共享多个对象所共有的相同状态,从而让我们能在有限的内存容量中载入更多对象。从这个定义中你可以发现,享元模式要解决的核心问题就是节约内存空间,使用的办法是找出相似对象之间的共有特征,然后复用这些特征。所谓“享元”,顾名思义就是被共享的单元。
比如: 一个文本字符串中存在很多重复的字符,如果每一个字符都用一个单独的对象来表示,将会占用较多的内存空间,我们可以使用享元模式解决这一类问题。

享元模式通过共享技术实现相同或者相似对象的重用,在逻辑上每一个出现的字符都有一个对象与之对应,然而在物理上他们却是共享同一个享元对象。

1.2 享元模式原理

1.2.1 享元模式类图

1.2.2 模式角色说明

享元模式的主要有以下角色:

  • 抽象享元角色(Flyweight):

通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。享元(Flyweight)模式中存在以下两种状态:

  1. 内部状态,即不会随着环境的改变而改变的可共享部分。
  2. 外部状态,指随环境改变而改变的不可以共享的部分。享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。
  • 可共享的具体享元(Concrete Flyweight)角色 :

它实现了抽象享元类,称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。

  • 非共享的具体享元(Unshared Flyweight)角色 :

并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。

  • 享元工厂(Flyweight Factory)角色 :

负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

1.2.3 示例代码

package main.java.cn.test.flyweight.V1;/*** @author ningzhaosheng* @date 2024/1/14 17:20:06* @description 抽象享元类*/
public abstract class Flyweight {public abstract void operation(String extrinsicState);
}
package main.java.cn.test.flyweight.V1;/*** @author ningzhaosheng* @date 2024/1/14 17:20:46* @description 可共享-具体享元类*/
public class ConcreteFlyweight extends Flyweight {//内部状态 intrinsicState作为成员变量,同一个享元对象的内部状态是一致的private String intrinsicState;public ConcreteFlyweight(String intrinsicState) {this.intrinsicState = intrinsicState;}/*** 外部状态在使用时由外部设置,不保存在享元对象中,即使是同一个对象** @param extrinsicState 外部状态,每次调用可以传入不同的外部状态*/@Overridepublic void operation(String extrinsicState) {//实现业务方法System.out.println("=== 享元对象内部状态" + intrinsicState + ",外部状态:" + extrinsicState);}}
package main.java.cn.test.flyweight.V1;/*** @author ningzhaosheng* @date 2024/1/14 17:23:16* @description 非共享具体享元类*/
public class UnsharedConcreteFlyweight extends Flyweight {private String intrinsicState;public UnsharedConcreteFlyweight(String intrinsicState) {this.intrinsicState = intrinsicState;}@Overridepublic void operation(String extrinsicState) {System.out.println("=== 使用不共享对象,内部状态: " + intrinsicState + ",外部状态: " + extrinsicState);}
}
package main.java.cn.test.flyweight.V1;import java.util.HashMap;
import java.util.Map;/*** @author ningzhaosheng* @date 2024/1/14 17:25:01* @description 享元工厂类* 作用: 作为存储享元对象的享元池.用户获取享元对象时先从享元池获* 取,有则返回,没有创建新的享元对象返回给用户,并在享元池中保存新增的对象.*/
public class FlyweightFactory {//定义一个HashMap用于存储享元对象,实现享元池private Map<String, Flyweight> pool = new HashMap();public FlyweightFactory() {//添加对应的内部状态pool.put("A", new ConcreteFlyweight("A"));pool.put("B", new ConcreteFlyweight("B"));pool.put("C", new ConcreteFlyweight("C"));}//根据内部状态来进行查找public Flyweight getFlyweight(String key) {//对象存在,从享元池直接返回if (pool.containsKey(key)) {System.out.println("===享元池中存在,直接复用,key:" + key);return pool.get(key);} else {//如果对象不存在,先创建一个新的对象添加到享元池中,然后返回System.out.println("===享元池中不存在,创建并复用, key:" + key);Flyweight fw = new ConcreteFlyweight(key);pool.put(key, fw);return fw;}}
}

二、享元模式的应用

2.1 需求说明

五子棋中有大量的黑子和白子,它们的形状大小都是一样的,只是出现的位置不同,所以一个棋子作为一个独立的对象存储在内存中,会导致大量的内存的浪费,我们使用享元模式来进行优化。

2.2 需求实现

2.2.1 类图

2.2.2 具体实现

2.2.2.1 抽象享元类
package main.java.cn.test.flyweight.V2;/*** @author ningzhaosheng* @date 2024/1/14 17:34:28* @description 抽象享元类: 五子棋类*/
public abstract class GobangFlyweight {public abstract String getColor();public void display() {System.out.println("棋子颜色: " + this.getColor());}}
2.2.2.2 共享享元类-白色棋子
package main.java.cn.test.flyweight.V2;/*** @author ningzhaosheng* @date 2024/1/14 17:35:10* @description 共享享元类-白色棋子*/
public class WhiteGobang extends GobangFlyweight{@Overridepublic String getColor() {return "白色";}
}
2.2.2.3 共享享元类-黑色棋子
package main.java.cn.test.flyweight.V2;/*** @author ningzhaosheng* @date 2024/1/14 17:35:45* @description 共享享元类-黑色棋子*/
public class BlackGobang extends GobangFlyweight {@Overridepublic String getColor() {return "黑色";}
}
2.2.2.4 享元工厂类
package main.java.cn.test.flyweight.V2;import java.util.HashMap;
import java.util.Map;/*** @author ningzhaosheng* @date 2024/1/14 17:36:19* @description 享元工厂类-生产围棋棋子,使用单例模式进行设计*/
public class GobangFactory {private static GobangFactory factory = new GobangFactory();private static Map<String, GobangFlyweight> pool;//设置共享对象的内部状态,在享元对象中传递private GobangFactory() {pool = new HashMap<String, GobangFlyweight>();GobangFlyweight black = new BlackGobang(); //黑子GobangFlyweight white = new WhiteGobang(); //白子pool.put("b", black);pool.put("w", white);}//返回享元工厂类唯一实例public static final GobangFactory getInstance() {return SingletonHolder.INSTANCE;}//静态内部类-单例private static class SingletonHolder {private static final GobangFactory INSTANCE = new GobangFactory();}//通过key获取集合中的享元对象public GobangFlyweight getGobang(String key) {return pool.get(key);}}
2.2.2.5 测试类
package main.java.cn.test.flyweight.V2;/*** @author ningzhaosheng* @date 2024/1/14 17:37:45* @description 测试类*/
public class Test {public static void main(String[] args) {//获取享元工厂对象GobangFactory instance = GobangFactory.getInstance();//获取3颗黑子GobangFlyweight b1 = instance.getGobang("b");GobangFlyweight b2 = instance.getGobang("b");GobangFlyweight b3 = instance.getGobang("b");System.out.println("判断两颗黑子是否相同: " + (b1 == b2));//获取2颗白子GobangFlyweight w1 = instance.getGobang("w");GobangFlyweight w2 = instance.getGobang("w");System.out.println("判断两颗白子是否相同: " + (w1 == w2));//显示棋子b1.display();b2.display();b3.display();w1.display();w2.display();}
}

三、享元模式总结

3.1 享元模式的优点

  • 极大减少内存中相似或相同对象数量,节约系统资源,提供系统性能

比如,当大量商家的商品图片、固定文字(如商品介绍、商品属性)在不同的网页进行展示时,通常不需要重复创建对象,而是可以使用同一个对象,以避免重复存储而浪费内存空间。由于通过享元模式构建的对象是共享的,所以当程序在运行时不仅不用重复创建,还能减少程序与操作系统的 IO 交互次数,大大提升了读写性能。

  • 享元模式中的外部状态相对独立,且不影响内部状态

3.2 享元模式的缺点

  • 为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,使程序逻辑复杂

3.3 享元模式的适用场景

  • 一个系统有大量相同或者相似的对象,造成内存的大量耗费。

注意: 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,应当在需要多次重复使用享元对象时才值得使用享元模式。

  • 在 Java 中,享元模式一个常用的场景就是,使用数据类的包装类对象的valueOf() 方法。

比如,使用 Integer.valueOf() 方法时,实际的代码实现中有一个叫 IntegerCache 的静态类,它就是一直缓存了 -127 到 128 范围内的数值,如下代码所示,你可以在 Java JDK 中的 Integer 类的源码中找到这段代码。

package main.java.cn.test.flyweight.V2;/*** @author ningzhaosheng* @date 2024/1/14 17:47:05* @description*/
public class Test1 {public static void main(String[] args) {Integer i1 = 127;Integer i2 = 127;System.out.println("i1和i2对象是否是同一个对象?" +(i1 == i2));Integer i3 = 128;Integer i4 = 128;System.out.println("i3和i4对象是否是同一个对象?" +(i3 == i4));}//传入的值在-128 - 127 之间,直接从缓存中返回public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
}

可以看到 Integer 默认先创建并缓存 -128 ~ 127 之间数的 Integer 对象,当调用 valueOf 时如果参数在 -128 ~ 127 之间则计算下标并从缓存中返回,否则创建一个新的 Integer 对象。其实享元模式本质上就是找到对象的不可变特征,并缓存起来,当类似对象使用时从缓存中读取,以达到节省内存空间的目的。

好了,本次分享就到这里,欢迎大家继续阅读《设计模式》专栏其他设计模式内容,如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!

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

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

相关文章

计算机网络——运输层(1)暨小程送书

计算机网络——运输层&#xff08;1&#xff09;暨小程送书 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 运输层概述两个主要协议运输层和网络层的关系网络层运输层总结 多路复用与多路分解多路复用多路分解不同的技术实现时分复用&#xff08;TDM&#xff09;频分复…

[STM32F407ZET6] GPIO

GPIO模式 F4的GPIO功能比F1的功能更多一些, 但是整体框架一样. F4的输出配置和F1的不同, F4的配置后, 施密特触发器将会开启, 还会对输入寄存器进行采样读取. F1的配置后, 推挽输出将会关闭施密特触发器, 开漏模式读取会读输入寄存器, 推挽模式会读取输出寄存器的值. 输出(全…

Java毕业设计-基于jsp+servlet的家用电器购物商城管理系统-第87期

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于jspservlet的家用电器购物商城管理系统&#xff1a;前端 jsp、jquery、layui&#xff0c;后端 servlet、jdbc&#xff0c;角色分为管理员、用户&#xff1b;集成商品…

分布式Erlang/OTP(学习笔记)(一)

Erlang分布式基础 假设你在机器A和机器B上各跑着一个Simple Cache应用的实例。要是在机器A的缓存上插人一个键/值对之后&#xff0c;从机器B上也可以访问&#xff0c;那可就好了。显然&#xff0c;要达到这个目的&#xff0c;机器A必须以某种方式将相关信息告知给机器B。传递该…

macOS向ntfs格式的移动硬盘写数据

最近想把日常拍摄的照片从SD存储卡中转存到闲置的移动硬盘中&#xff0c;但是转存的时候发现&#xff0c;mac只能读我硬盘里的东西&#xff0c;无法将数据写入到移动硬盘中&#xff0c;也无法删除移动硬盘的数据。后来在网上查了许久资料&#xff0c;终于可实现mac对移动硬盘写…

修改iview的表格table展开的默认icon和样式

修改前 修改后 修改内容 .title_label_list .ivu-icon-ios-add{font-size: 26px;color: #888888; } .title_label_list .ivu-icon-ios-add:hover{color: #11AAAA; } .title_label_list .ivu-icon-ios-add:before {content: "\F341"; } .title_label_list .ivu-icon-…

Vue3/Vue2实现文章内容中多个“关键词“标记高亮显示

一、实现效果 下拉列表高亮展示关键词 二、实现思路 安装 “vue-word-highlighter” &#xff0c;这是一个 支持 Vue3 和 Vue2&#xff0c;不过 Vue2 版本是通过 vue-demi 构建的 三、案例代码 package.json "vue-word-highlighter": "^1.0.4"Vue3 …

银河麒麟服务器操作系统搭建证书服务器并颁发可用于签名的证书步骤说明

银河麒麟服务器操作系统搭建证书服务器并颁发可用于签名的证书的方法与前面Centos7上&#xff08;centos7 使用openssl 配置证书服务器并颁发证书&#xff08;史上最详细版本&#xff09;_centos phpinfo显示的openssl配置项为/etc/pki/tls/openssl.c-CSDN博客&#xff09;是一…

【计算机组成与体系结构Ⅱ】多Cache一致性的模拟分析(实验)

实验八&#xff1a;多Cache一致性的模拟分析 一、实验目的 1&#xff1a;加深对多 Cache 一致性的理解。 2&#xff1a;进一步掌握解决多 Cache一致性的目录协议和监听协议的基本思想。 3&#xff1a;掌握在各种情况下&#xff0c; 目录协议和监听协议是如何工作的&#xf…

跨Android、iOS、鸿蒙多平台框架ArkUI-X

ArkUI是一套构建分布式应用界面的声明式UI开发框架。它使用极简的UI信息语法、丰富的UI组件、以及实时界面预览工具&#xff0c;帮助您提升移动应用界面开发效率30%。您只需使用一套ArkTS API&#xff0c;就能在Android、iOS、鸿蒙多个平台上提供生动而流畅的用户界面体验。 一…

16.7 基于递归神经网络的分层多楼多层室内定位

文献来源&#xff1a;西交利物浦大学 Elesawi A E A, Kim K S. Hierarchical multi-building and multi-floor indoor localization based on recurrent neural networks[C]//2021 Ninth International Symposium on Computing and Networking Workshops (CANDARW). IEEE, 202…

MySQL优化之SQL调优策略

首先以一张思维导图从全局上给大家分享以下几种SQL优化策略&#xff0c;再详细讲解 1、避免使用SELECT * 在阿里的编码规范中也强制了数据库查询不能使用SELECT *&#xff0c;因为SELECT *方式走的都是全表扫描&#xff0c;导致的结果就是查询效率非常低下&#xff0c;其原因为…

苹果笔记本 macbook 在 office word 中使用 mathtype 的方法

前言 想在 MacBook 中使用 mathtype&#xff0c;去搜索&#xff0c;去 Apple Store 下载也发现没有 解决方法 打开 office Word 的「插入」中的「获取加载项」、「我的加载项」。 在应用商店中下载&#xff0c;需要登录自己的微软账号。 加载成功后就可以使用了。 注意 和…

【Unity实战100例】Unity对Ini格式的配置文件管理和读写

目录 一.编写ini格式配置文件 二.读取解析ini文件 三.调用属性 INI 文件以文本形式存储,易于阅读和编辑。这种人可读的格式使得调整配置参数变得更加直观,不需要专门的工具。 INI 文件是一种轻量级的配置文件格式,不需要复杂的解析器或库。它的结构相对简单,适用于小到

What is `addFormattersdoes` in `WebMvcConfigurer` ?

addFormatters 方法在SpringMVC框架中主要用于向Spring容器注册自定义的格式化器&#xff08;Formatter&#xff09; SpringMVC内置了一系列的标准格式化器&#xff0c;用于处理日期、数字和其他常见类型的转换。 开发者也可以通过实现 WebMvcConfigurer 接口&#xff0c;并重写…

Unix时间戳

时间戳&#xff0c;相信很多相关专业的人&#xff0c;计算机软件电子等等都会听过。由于最早是由Unix系统使用所以又叫Unix时间戳。 Unix 时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC&#xff08;世界协调时&#xff09;/GMT&#xff08;格林尼治时&#xff09;…

内网穿透的应用-使用Docker搭建一个Wiki.Js知识库系统并实现分享他人远程创作

文章目录 1. 安装Docker2. 获取Wiki.js镜像3. 本地服务器打开Wiki.js并添加知识库内容4. 实现公网访问Wiki.js5. 固定Wiki.js公网地址 不管是在企业中还是在自己的个人知识整理上&#xff0c;我们都需要通过某种方式来有条理的组织相应的知识架构&#xff0c;那么一个好的知识整…

KNN算法原理及应用

理解KNN 算法原理 KNN是监督学习分类算法&#xff0c;主要解决现实生活中分类问题。 根据目标的不同将监督学习任务分为了分类学习及回归预测问题。 监督学习任务的基本流程和架构&#xff1a; &#xff08;1&#xff09;首先准备数据&#xff0c;可以是视频、音频、文本、…

【C++】STL 算法 - 累加填充算法 ( 元素累加算法 - accumulate 函数 | 元素填充算法 - fill 函数 )

文章目录 一、元素累加算法 - accumulate 函数1、函数原型分析2、代码示例 二、元素填充算法 - fill 函数1、函数原型分析2、代码示例 一、元素累加算法 - accumulate 函数 1、函数原型分析 在 C 语言 的 标准模板库 ( STL , STL Standard Template Library ) 中 , 提供了 accu…

晶格动力学 GULP 软件的安装步骤

---------------------------------------------------------------------- GULP软件现已发展到5.2版本&#xff0c;其使用Fortran编译器&#xff0c;可运行在Linux/Unix系统下&#xff0c;但不提供任何Windows版本的技术支持。 下载网址&#xff1a; http://gulp.curtin.ed…