2.7 享元模式
享元模式(Flyweight)是一个纯粹为内存而生的模式。当你需要海量细粒度对象(几十万棵树、整页文档的每个字符、地图上的每个图标),把每个对象都完整地造出来会撑爆内存。享元把对象的状态拆成两半:
- 内蕴状态(intrinsic):可共享、不随上下文变化的部分,例如树的种类、贴图、字符的字形。
- 外蕴状态(extrinsic):因对象而异、不能共享的部分,例如坐标、颜色实例。
内蕴状态被抽出来,在所有对象间共享同一份;外蕴状态由客户端在调用时传入。
下面的森林实验:你种下成百上千棵树,但右上角会显示真正创建的“享元对象”其实只有寥寥几个。
正在加载交互实验...
工厂负责复用
java
class TreeFactory {
private static Map<String, TreeType> pool = new HashMap<>();
static TreeType get(String name) {
return pool.computeIfAbsent(name, TreeType::new); // 已有就复用
}
}
// 外蕴状态在使用时传入,不存进享元
treeType.draw(canvas, x, y);关键:坐标 x, y 绝不能存进 TreeType,否则就无法共享了。下面的对照器用滑块调整对象数量,量化“用 vs 不用享元”的内存差距。
正在加载交互实验...
正在加载概念检查...
代价与边界
享元不是免费的:
- 你必须清晰地切分内蕴 / 外蕴状态,这会让代码更绕。
- 享元对象通常要做成不可变的(既然被共享,就不能被某个使用者偷偷改掉)。
- 如果对象数量本就不大,享元只会徒增复杂度。
一句话:享元是一种用 CPU/复杂度换内存的优化,只在内存确实是瓶颈、且对象高度重复时才值得。Java 的 Integer.valueOf() 缓存(-128~127)就是一个内置的享元。
正在加载概念检查...
正在加载本节练习...