享元模式(Flyweight Pattern)

通过共享对象来减少内存使用和提高性能,适用于大量相似对象需要被创建的场景。

概念定义

享元模式(Flyweight Pattern) 的核心是为了解决大量对象存在时,可能造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回内存已有的对象,避免重新创建。

核心结构

角色 职责
Flyweight(抽象享元类) 定义公共接口或抽象类,用于管理内部状态。
ConcreteFlyweight(具体享元类) 实现Flyweight接口,存储内部状态
UnsharedConcreteFlyweight(非共享具体享元类) 不可共享的对象(Option)
FlyweightFactory(享元工厂) 负责创建和管理享元对象,确保对象复用

示例:围棋棋子渲染系统

假设我们开发一个围棋游戏,棋盘上有几百个棋子,它们有相同的形状但不同的颜色和位置。

伪代码如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public interface Piece {
void render(int x, int y);
}
public class WhitePiece implements Piece {
@Override
public void render(int x, int y); // 绘制白色棋子
}
public class BlackPiece implements Piece {
@Override
public void render(int x, int y); // 绘制黑色棋子
}

public class PieceFactory {
private static final Map<String, Piece> pieces = new HashMap<>();
public static Piece getPiece(String type) {
if (!pieces.containsKey(type)) {
switch (type) {
case "white":
pieces.put(type, new WhitePiece()); //
break;
case "black":
pieces.put(type, new BlackPiece());
break;
default:
throw new IllegalArgumentException("Invalid piece type: " + type);
}
}
return pieces.get(type);
}
}

这种暂存的享元模式实际上在开发中非常常见,并且会有意无意中用到。

1
2
3
4
5
6
7
8
void main() {
for (int i = 0; i < 100; i++) {
var black = PieceFactory.getPiece("black");
black.render(i%10, i/10);
var white = PieceFactory.getPiece("white");
white.render(i%10, i/10);
}
}
  • 如果不使用享元模式,100黑子+100白子=创建200个对象。
  • 使用享元后: 只创建2个对象(一个黑子、一个白子),重复调用render(x, y)即可。

实际应用场景

应用 描述
文本编辑器 字符样式共享(字体、大小、颜色),位置作为外部 状态
游戏开发 子弹、敌人、道具等大量重复实体对象(早期像素游戏)
图形界面库 按钮、图标、字体等图形资源缓存
数据库连接池 复用数据库连接对象

总结

享元模式的核心思想是“共享不变、分离变化”,适用于大量相似对象的复用场景。