1. 什么是享元模式?
享元模式(Flyweight Pattern)是一种结构型设计模式,通过共享对象来减少内存占用,从而高效支持大量细粒度的对象。其核心思想是分离对象的内部状态(可共享)和外部状态(不可共享),通过共享内部状态来避免重复创建对象。
2. 核心概念
内部状态:对象中不变的部分,可以被多个对象共享(例如:颜色、字体)。
外部状态:对象中变化的部分,由客户端传入(例如:位置、尺寸)。
3. 模式结构
Flyweight:定义享元对象的接口(例如:
Shape
)。ConcreteFlyweight:实现享元接口,保存内部状态(例如:
ColorShape
)。FlyweightFactory:创建并管理享元对象池,确保共享(例如:
ShapeFactory
)。
4. 实现示例:图形绘制系统
假设需要绘制大量不同颜色的圆形,颜色是内部状态,坐标是外部状态。
步骤 1:定义享元接口
public interface Shape { void draw(int x, int y); // 外部状态由参数传入 }
步骤 2:实现具体享元类
public class ColorShape implements Shape { private final String color; // 内部状态(不可变) public ColorShape(String color) { this.color = color; } @Override public void draw(int x, int y) { System.out.println( "Drawing " + color + " circle at (" + x + ", " + y + ")" ); } }
步骤 3:创建享元工厂
import java.util.HashMap; import java.util.Map; public class ShapeFactory { private static final Map<String, Shape> shapes = new HashMap<>(); public static Shape getShape(String color) { // 如果颜色不存在,则创建新对象并缓存 Shape shape = shapes.computeIfAbsent(color, ColorShape::new); return shape; } }
步骤 4:客户端使用
public class Client { public static void main(String[] args) { // 获取红色圆形(首次创建) Shape redCircle = ShapeFactory.getShape("red"); redCircle.draw(10, 20); // 传入外部状态坐标 // 再次获取红色圆形(共享已有对象) Shape sameRedCircle = ShapeFactory.getShape("red"); sameRedCircle.draw(30, 40); // 验证是否为同一对象 System.out.println("Same instance? " + (redCircle == sameRedCircle)); // 获取蓝色圆形(创建新对象) Shape blueCircle = ShapeFactory.getShape("blue"); blueCircle.draw(50, 60); } }
输出结果
Drawing red circle at (10, 20) Drawing red circle at (30, 40) Same instance? true Drawing blue circle at (50, 60)
5. 享元模式在 JDK 中的应用
Integer.valueOf(int)
:缓存了 -128 到 127 的整数对象。String
常量池:相同字符串字面量指向同一内存。
6. 适用场景
系统中存在大量相似对象。
对象的大部分状态可以外部化。
需要减少内存消耗或对象创建开销。
7. 优缺点
优点:
大幅减少内存占用。
提高性能(减少对象创建和垃圾回收)。
缺点:
增加系统复杂度(需分离内外状态)。
线程安全问题需额外处理(共享对象可能被多线程修改)。
8. 扩展思考
外部状态管理:通常由客户端维护外部状态,享元对象仅处理内部状态。
复合享元:将多个享元组合成树形结构,支持更复杂的共享逻辑。
通过合理使用享元模式,可以在处理大量细粒度对象时显著优化资源利用。