享元
更新: 6/22/2025 字数: 0 字 时长: 0 分钟
定义
享元模式 (Flyweight Pattern) 运用共享技术有效地支持大量细粒度对象的复用。通过分离对象的内在状态(可共享)和外在状态(不可共享),享元模式显著减少内存占用,提高系统性能。
角色
- 享元接口 (Flyweight):声明对象操作接口
- 具体享元 (Concrete Flyweight):实现享元接口,存储内在状态
- 非共享具体享元 (Unshared Concrete Flyweight):不共享的具体实现
- 享元工厂 (Flyweight Factory):创建和管理享元对象
- 客户端 (Client):维护外在状态,使用享元对象
实现
文本编辑器字符示例
java
// 享元接口
public interface Character {
void display(int position);
}
// 具体享元:字符对象
public class CharacterImpl implements Character {
private char symbol; // 内在状态(可共享)
public CharacterImpl(char symbol) {
this.symbol = symbol;
}
@Override
public void display(int position) {
System.out.println("字符 '" + symbol + "' 在位置:" + position);
}
}
// 享元工厂
public class CharacterFactory {
private Map<Character, Character> characters = new HashMap<>();
public Character getCharacter(char symbol) {
Character character = characters.get(symbol);
if (character == null) {
character = new CharacterImpl(symbol);
characters.put(symbol, character);
}
return character;
}
}
// 客户端:文档
public class Document {
private List<Character> chars = new ArrayList<>();
private CharacterFactory factory = new CharacterFactory();
public void addChar(char symbol, int position) {
Character character = factory.getCharacter(symbol);
chars.add(character);
character.display(position);
}
public void saveToFile(String filename) {
// 保存文档(只存储字符和位置)
}
}
// 使用示例
public class TextEditor {
public static void main(String[] args) {
Document doc = new Document();
doc.addChar('H', 1);
doc.addChar('e', 2);
doc.addChar('l', 3);
doc.addChar('l', 4); // 重用'l'享元
doc.addChar('o', 5);
}
}
游戏粒子系统示例
java
// 内在状态(可共享)
public class ParticleType {
private String name;
private String texture;
private Color color;
public ParticleType(String name, String texture, Color color) {
this.name = name;
this.texture = texture;
this.color = color;
}
public void draw(Particle particle) {
// 使用内在状态绘制粒子
System.out.printf("绘制 %s 粒子:位置 (%d,%d), 速度 (%d,%d)%n",
name, particle.getX(), particle.getY(),
particle.getVelX(), particle.getVelY());
}
}
// 外在状态(不可共享)
public class Particle {
private int x, y; // 位置
private int velX, velY; // 速度
private ParticleType type; // 享元引用
public Particle(int x, int y, int velX, int velY, ParticleType type) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.type = type;
}
public void move() {
x += velX;
y += velY;
}
public void draw() {
type.draw(this);
}
// getters...
}
// 享元工厂
public class ParticleFactory {
private Map<String, ParticleType> particleTypes = new HashMap<>();
public ParticleType getParticleType(String name, String texture, Color color) {
String key = name + texture + color.toString();
ParticleType type = particleTypes.get(key);
if (type == null) {
type = new ParticleType(name, texture, color);
particleTypes.put(key, type);
}
return type;
}
}
// 粒子系统(客户端)
public class ParticleSystem {
private List<Particle> particles = new ArrayList<>();
private ParticleFactory factory = new ParticleFactory();
public void addParticle(int x, int y, int velX, int velY,
String typeName, String texture, Color color) {
ParticleType type = factory.getParticleType(typeName, texture, color);
particles.add(new Particle(x, y, velX, velY, type));
}
public void animate() {
for (Particle particle : particles) {
particle.move();
particle.draw();
}
}
}
优缺点
优点:
- 大幅减少内存占用
- 减少对象创建开销
- 集中管理共享状态
- 提高系统性能(尤其大量重复对象场景)
缺点:
- 增加系统复杂度
- 需要分离内外状态(增加设计难度)
- 共享对象线程安全问题
- 可能引入查找开销(工厂查找)
应用场景
- 大量相似对象占用过多内存
- 对象状态可分离为内在和外在
- 不依赖对象标识的操作
- 文本编辑器(字符处理)
- 游戏开发(粒子、地形、NPC)
- 图形系统(图标、光标)
- 数据库连接池
与其他模式的关系
- 与组合模式:享元可作为组合中的叶子节点
- 与单例模式:享元工厂常使用单例
- 与状态模式:状态对象可实现为享元
- 与策略模式:策略对象可实现为享元
- 与对象池模式:对象池管理生命周期,享元关注状态共享
JDK 中的享元模式
- Java 字符串常量池
java.lang.Integer#valueOf()
(-128~127 缓存)java.lang.Boolean#valueOf()
(TRUE/FALSE 缓存)- Swing 中的
Border
实现 - Java 线程池(线程复用)
注意事项
- 仔细分析对象状态(区分内在/外在)
- 控制享元对象数量(避免工厂膨胀)
- 考虑线程安全(共享状态访问)
- 避免过早优化(只在必要时使用)
- 注意享元对象生命周期管理
- 平衡内存节省与性能开销