在软件开发中,我们经常会遇到一些对象包含大量重复的属性(如样式信息、配置数据等),如果每个对象都独立存储这些数据,会导致内存浪费。如何让多个对象共享相同的属性,从而减少内存占用?这时,享元模式(Flyweight Pattern) 就能派上用场!
本文将介绍:
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享相同数据来减少内存使用。其核心思想是:
目标:让多个对象共享相同的内部状态,避免重复存储,从而节省内存。
假设我们有一个 Text
类,每个 Text
对象可能包含相同的 TextStyle
(如字体、颜色)。我们可以用享元模式优化内存:
public final class TextStyle {
private final String fontFamily;
private final int fontSize;
private final boolean isBold;
private final String color;
public TextStyle(String fontFamily, int fontSize, boolean isBold, String color) {
this.fontFamily = fontFamily;
this.fontSize = fontSize;
this.isBold = isBold;
this.color = color;
}
// Getters...
public String getFontFamily() { return fontFamily; }
public int getFontSize() { return fontSize; }
public boolean isBold() { return isBold; }
public String getColor() { return color; }
}
import java.util.HashMap;
import java.util.Map;
public class TextStyleFactory {
private static final Map<String, TextStyle> textStylePool = new HashMap<>();
public static TextStyle getTextStyle(String fontFamily, int fontSize, boolean isBold, String color) {
String key = fontFamily + "-" + fontSize + "-" + isBold + "-" + color;
// 如果存在,直接返回缓存的样式
if (textStylePool.containsKey(key)) {
return textStylePool.get(key);
}
// 否则创建并缓存
TextStyle style = new TextStyle(fontFamily, fontSize, isBold, color);
textStylePool.put(key, style);
return style;
}
}
public class Text {
private final String content; // 外部状态(不可共享)
private final TextStyle textStyle; // 内部状态(可共享)
public Text(String content, TextStyle textStyle) {
this.content = content;
this.textStyle = textStyle;
}
public void render() {
System.out.printf(
"Rendering text: '%s' with style: %s, %dpx, %s, %s\n",
content,
textStyle.getFontFamily(),
textStyle.getFontSize(),
textStyle.isBold() ? "bold" : "normal",
textStyle.getColor()
);
}
}
public class Client {
public static void main(String[] args) {
// 共享的 TextStyle
TextStyle style1 = TextStyleFactory.getTextStyle("Arial", 12, true, "red");
TextStyle style2 = TextStyleFactory.getTextStyle("Arial", 12, true, "red"); // 返回缓存的 style1
Text text1 = new Text("Hello", style1);
Text text2 = new Text("World", style2); // style2 实际上是 style1 的引用
text1.render();
text2.render();
// 检查是否共享同一个对象
System.out.println("Is style1 == style2? " + (style1 == style2)); // true
}
}
运行结果:
Rendering text: 'Hello' with style: Arial, 12px, bold, red
Rendering text: 'World' with style: Arial, 12px, bold, red
Is style1 == style2? true
✅ 适合使用享元模式的情况:
❌ 不适合的情况:
String
常量池:相同的字符串字面量会共享同一个对象。Color
、Font
等可共享对象。✔ 减少内存占用:共享相同数据,避免重复存储。
✔ 提高性能:减少对象创建和垃圾回收的开销。
✖ 增加代码复杂度:需要分离内部状态和外部状态。
✖ 线程安全问题:如果享元对象被修改,可能影响所有引用它的对象(通常享元对象应该是不可变的)。
TextStyle
)。TextStyleFactory
)管理共享对象。如果你的应用中有大量重复数据,享元模式 能帮你显著优化内存!