享元模式
Flyweight — 共享细粒度对象,大幅减少内存使用
一句话理解
当系统中有大量相似对象时,把它们共同的部分提取出来共享,避免重复创建。
解决什么问题
假设一个文本编辑器要渲染 10 万个字符,如果每个字符都创建一个包含字体、大小、颜色等信息的对象,内存会爆。享元模式把"字体+大小+颜色"这些不变的部分抽出来共享。
核心概念:
- 内部状态(Intrinsic):不变的、可共享的(如字体、颜色)
- 外部状态(Extrinsic):变化的、不可共享的(如字符位置)
怎么写
// 享元对象:棋子样式(可共享的内部状态)
public class ChessPiece {
private final String color; // 黑/白
private final String shape; // 棋子造型
public ChessPiece(String color, String shape) {
this.color = color;
this.shape = shape;
}
// 外部状态(位置)由外部传入
public void place(int x, int y) {
System.out.println(color + shape + " 放在 (" + x + "," + y + ")");
}
}
// 享元工厂:缓存并复用已创建的对象
public class ChessPieceFactory {
private static final Map<String, ChessPiece> cache = new HashMap<>();
public static ChessPiece get(String color) {
return cache.computeIfAbsent(color,
c -> new ChessPiece(c, "●"));
}
}// 使用:无论创建多少个同色棋子,内存中只有一个对象
ChessPiece b1 = ChessPieceFactory.get("黑");
ChessPiece b2 = ChessPieceFactory.get("黑");
System.out.println(b1 == b2); // true,同一个对象
b1.place(0, 0); // 黑● 放在 (0,0)
b2.place(1, 1); // 黑● 放在 (1,1) —— 同一个享元,不同的外部状态Java 中的享元
// String 常量池就是享元模式
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true,共享同一个对象
// Integer 缓存池(-128 ~ 127)
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true,从缓存取
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false,超出缓存范围使用场景
String常量池Integer/Long等包装类的缓存- 线程池、连接池 —— 复用已有对象而非每次新建
- 游戏中大量相同类型的对象(子弹、粒子效果)