通过共享对象来减少内存使用和提高性能,适用于大量相似对象需要被创建的场景。
概念定义
享元模式(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)
即可。
实际应用场景
应用 |
描述 |
文本编辑器 |
字符样式共享(字体、大小、颜色),位置作为外部 状态 |
游戏开发 |
子弹、敌人、道具等大量重复实体对象(早期像素游戏) |
图形界面库 |
按钮、图标、字体等图形资源缓存 |
数据库连接池 |
复用数据库连接对象 |
总结
享元模式的核心思想是“共享不变、分离变化”,适用于大量相似对象的复用场景。