Day38 【概念解析】享元模式
目录 ▼
整理定义
中文名称:享元模式
英文名称:flyweight pattern
复述展开
What is flyweight?
剑桥英语字典:
flyweight :a boxer who is in the lightest weight group, weighing 51 kilograms or less
蝇量级:体重最轻的拳击手,体重 51 公斤或以下
在设计模式中,使用了意译的方式进行翻译,唤作“享元模式”。
享元 = 共享元素
该模式的核心在于对于大量出现的细粒度的元素进行共享,从而减少内存的消耗。
What is Flyweight pattern?
📌 享元模式,是一种结构型对象设计模式,它通过提供可以被大量共享的细粒度对象,从而减少存储空间。该模式适用于有可以大量共享复用的元素物件的场景,例如游戏、编辑器。
🌰*1 富文本编辑器的字母对象
富文本编辑器在英文环境下,其中的文本由大量字母组成,为了便于做统一的格式化、计算等处理,需要将每个字母都存储为对象,但这样存储的代价太大了。
已知英文字母一共 26 个,所以文档中存在大量重复使用的字母,而每个字母除了位置信息外,其它信息都是相同且只读的,那么有办法降低富文本场景巨大的字母对象数量吗?
🌰*2 网盘存储
当我们上传一部电影时,有时候几十 GB 的内容不到一秒就上传完了,这是网盘提示你,“已采用极速技术秒传”,你会不会心生疑惑,这么厉害的技术为什么不能每次都生效?
另外,网盘存储时,同一部电影可能都会存放在不同用户的不同文件夹中,而且电影文件又特别巨大,和富文本类似,电影文件也只有存放位置是不同的,而其余内容都特别巨大且只读,有什么办法能优化存储呢?
🌰*3 大型多人游戏
玩多人游戏时,为了防止外挂,一般对象的创建与计算是在服务器完成的,那如何保证一个玩家拾取物品后,另一个玩家看到的物品会消失?
其实道理已经不言而喻了,虽然在不同客户端之间,游戏对象是相互独立的,但在一局游戏中,所有玩家的对象在服务器是共享的。
享元模式结构

-
享元模式只是一种优化。 在应用该模式之前, 你要确定程序中存在与大量类似对象同时占用内存相关的内存消耗问题, 并且确保该问题无法使用其他更好的方式来解决。
-
享元 (Flyweight) 类包含原始对象中部分能在多个对象中共享的状态。 同一享元对象可在许多不同情景中使用。 享元中存储的状态被称为 “内在状态”。 传递给享元方法的状态被称为 “外在状态”。
-
情景 (Context) 类包含原始对象中各不相同的外在状态。 情景与享元对象组合在一起就能表示原始对象的全部状态。
-
通常情况下, 原始对象的行为会保留在享元类中。 因此调用享元方法必须提供部分外在状态作为参数。 但你也可将行为移动到情景类中, 然后将连入的享元作为单纯的数据对象。
-
客户端 (Client) 负责计算或存储享元的外在状态。 在客户端看来, 享元是一种可在运行时进行配置的模板对象, 具体的配置方式为向其方法中传入一些情景数据参数。
-
享元工厂 (Flyweight Factory) 会对已有享元的缓存池进行管理。 有了工厂后, 客户端就无需直接创建享元, 它们只需调用工厂并向其传递目标享元的一些内在状态即可。 工厂会根据参数在之前已创建的享元中进行查找, 如果找到满足条件的享元就将其返回; 如果没有找到就根据参数新建享元。
理解体会
享元模式,顾名思义,就是将元素共享的模式。“共享” 就是享元模式的精髓,将那些大量的,具有很多内部状态而外部状态很少的对象进行共享,就是享元模式的使用方式。
不管使网盘使用的场景,还是大型在线游戏中,都使用了享元模式。就比如转存在自己网盘,顷刻间就完成了存储,实质上就是保存了一个网盘的一个索引,当要下载时都是从一个唯一的源进行下载。想想看,如果每个人都有1TB内存,百度云要多少云盘来存储,可能时进行了共享元素的优化。