享元模式
简介
定义: 运用共享技术有效地支持大量细粒度的对象。主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
使用场景:
文本编辑器的字符对象
游戏中的大量粒子、子弹
String常量池
Integer缓存(-128到127)
实现要点:
内部状态(可共享)
外部状态(不可共享)
享元工厂管理对象池
UML
代码示例
创建一个享元接口
public interface CharacterFlyweight {
/**
* 显示字符
* @param fontSize 字体大小(外部状态)
* @param color 颜色(外部状态)
* @param position 位置(外部状态)
*/
void display(int fontSize, String color, String position);
}享元实现
public class ConcreteCharacter implements CharacterFlyweight {
/**
* 内部状态:字符本身(可共享,不变)
*/
private final char character;
/**
* 构造函数
* @param character 字符(内部状态)
*/
public ConcreteCharacter(char character) {
this.character = character;
System.out.println("✨ 创建享元对象: '" + character + "'");
}
@Override
public void display(int fontSize, String color, String position) {
// 内部状态(character)+ 外部状态(fontSize, color, position)
System.out.println(String.format("字符: '%c' | 字号: %d | 颜色: %s | 位置: %s",
character, fontSize, color, position));
}
/**
* 获取字符
*/
public char getCharacter() {
return character;
}
}享元工厂
public class CharacterFactory {
/**
* 享元池:存储已创建的享元对象
* key: 字符, value: 享元对象
*/
private Map<Character, CharacterFlyweight> flyweightPool;
/**
* 单例模式:确保只有一个工厂实例
*/
private static CharacterFactory instance = new CharacterFactory();
/**
* 私有构造函数
*/
private CharacterFactory() {
flyweightPool = new HashMap<>();
}
/**
* 获取工厂实例
*/
public static CharacterFactory getInstance() {
return instance;
}
/**
* 获取字符享元对象
* 如果池中存在则返回,否则创建新对象并放入池中
*/
public CharacterFlyweight getCharacter(char c) {
CharacterFlyweight character = flyweightPool.get(c);
if (character == null) {
// 池中不存在,创建新对象
character = new ConcreteCharacter(c);
flyweightPool.put(c, character);
} else {
System.out.println("♻️ 复用享元对象: '" + c + "'");
}
return character;
}
/**
* 获取享元池大小
*/
public int getPoolSize() {
return flyweightPool.size();
}
/**
* 清空享元池
*/
public void clearPool() {
flyweightPool.clear();
System.out.println("🗑️ 享元池已清空");
}
/**
* 显示享元池状态
*/
public void showPoolStatus() {
System.out.println("\n📊 享元池状态:");
System.out.println(" 池中对象数量: " + flyweightPool.size());
System.out.println(" 已创建的字符: " + flyweightPool.keySet());
}
}客户端
public class Editor {
/**
* 字符列表(存储外部状态)
*/
private List<CharacterContext> characters;
private CharacterFactory factory;
public Editor() {
characters = new ArrayList<>();
factory = CharacterFactory.getInstance();
}
/**
* 插入字符
*/
public void insertCharacter(char c, int fontSize, String color, String position) {
// 从工厂获取享元对象
CharacterFlyweight flyweight = factory.getCharacter(c);
// 创建上下文,存储外部状态
CharacterContext context = new CharacterContext(flyweight, fontSize, color, position);
characters.add(context);
}
/**
* 显示文档内容
*/
public void display() {
System.out.println("\n📄 文档内容:");
System.out.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
for (CharacterContext context : characters) {
context.display();
}
System.out.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
}
/**
* 获取字符数量
*/
public int getCharacterCount() {
return characters.size();
}
/**
* 清空文档
*/
public void clear() {
characters.clear();
System.out.println("📄 文档已清空");
}
/**
* 字符上下文类 - 存储外部状态
*/
private static class CharacterContext {
private CharacterFlyweight flyweight;
private int fontSize;
private String color;
private String position;
public CharacterContext(CharacterFlyweight flyweight, int fontSize, String color, String position) {
this.flyweight = flyweight;
this.fontSize = fontSize;
this.color = color;
this.position = position;
}
public void display() {
flyweight.display(fontSize, color, position);
}
}
}使用方式
public class Test {
public static void main(String[] args) {
System.out.println("=== 享元模式 - 文本编辑器示例 ===\n");
// 创建文本编辑器
Editor editor = new Editor();
CharacterFactory factory = CharacterFactory.getInstance();
System.out.println("--- 场景1:输入文本 \"HELLO\" ---");
// 输入 HELLO
editor.insertCharacter('H', 12, "红色", "(0,0)");
editor.insertCharacter('E', 12, "蓝色", "(1,0)");
editor.insertCharacter('L', 12, "绿色", "(2,0)");
editor.insertCharacter('L', 12, "黄色", "(3,0)"); // L重复使用
editor.insertCharacter('O', 12, "紫色", "(4,0)");
// 显示享元池状态
factory.showPoolStatus();
System.out.println("\n--- 场景2:继续输入文本 \"WORLD\" ---");
// 输入 WORLD(部分字符已存在于享元池)
editor.insertCharacter('W', 14, "橙色", "(5,0)");
editor.insertCharacter('O', 14, "粉色", "(6,0)"); // O重复使用
editor.insertCharacter('R', 14, "青色", "(7,0)");
editor.insertCharacter('L', 14, "棕色", "(8,0)"); // L重复使用
editor.insertCharacter('D', 14, "灰色", "(9,0)");
// 显示享元池状态
factory.showPoolStatus();
// 显示文档内容
editor.display();
System.out.println("\n--- 场景3:输入长文本测试内存优化 ---");
String longText = "HELLO WORLD! THIS IS A FLYWEIGHT PATTERN DEMO!";
Editor editor2 = new Editor();
System.out.println("正在输入: \"" + longText + "\"");
System.out.println("文本长度: " + longText.length() + " 个字符\n");
for (int i = 0; i < longText.length(); i++) {
char c = longText.charAt(i);
editor2.insertCharacter(c, 12, "黑色", "(" + i + ",1)");
}
// 显示享元池状态
factory.showPoolStatus();
// 显示内存优化效果
System.out.println("\n📊 内存优化效果分析:");
System.out.println(" 文本总字符数: " + longText.length());
System.out.println(" 实际创建的对象数: " + factory.getPoolSize());
System.out.println(" 节省对象数: " + (longText.length() - factory.getPoolSize()));
System.out.println(" 内存节省率: " + String.format("%.1f%%",
(1 - (double)factory.getPoolSize() / longText.length()) * 100));
System.out.println("\n--- 场景4:对比不使用享元模式 ---");
System.out.println("\n❌ 不使用享元模式:");
System.out.println(" 每个字符都创建新对象");
System.out.println(" " + longText.length() + " 个字符需要创建 " + longText.length() + " 个对象");
System.out.println(" 内存占用: " + longText.length() + " × 对象大小");
System.out.println("\n✅ 使用享元模式:");
System.out.println(" 相同字符共享对象");
System.out.println(" " + longText.length() + " 个字符只需要创建 " + factory.getPoolSize() + " 个对象");
System.out.println(" 内存占用: " + factory.getPoolSize() + " × 对象大小 + 外部状态");
System.out.println(" 大大节省了内存!");
System.out.println("\n=== 享元模式说明 ===");
System.out.println("1. 享元接口: CharacterFlyweight - 定义享元对象的接口");
System.out.println("2. 具体享元: ConcreteCharacter - 实现享元接口,存储内部状态");
System.out.println("3. 享元工厂: CharacterFactory - 管理享元对象池");
System.out.println("4. 客户端: Editor - 维护外部状态,使用享元对象");
System.out.println("5. 内部状态: 字符本身(可共享)");
System.out.println("6. 外部状态: 字号、颜色、位置(不可共享)");
System.out.println("\n=== 享元模式优势 ===");
System.out.println("✅ 减少对象数量: 通过共享技术减少内存占用");
System.out.println("✅ 提高性能: 减少对象创建和垃圾回收开销");
System.out.println("✅ 适合大量相似对象: 特别适合大量细粒度对象");
System.out.println("✅ 外部状态分离: 将可变部分外部化");
System.out.println("\n=== 享元模式应用场景 ===");
System.out.println("📌 文本编辑器: 字符对象共享");
System.out.println("📌 游戏开发: 大量相同的粒子、子弹、树木等");
System.out.println("📌 图形界面: 大量相同的图标、按钮等");
System.out.println("📌 字符串常量池: Java String.intern()");
System.out.println("📌 数据库连接池: 连接对象复用");
System.out.println("📌 线程池: 线程对象复用");
System.out.println("\n=== 享元模式关键点 ===");
System.out.println("🔑 内部状态: 存储在享元对象内部,可以共享");
System.out.println("🔑 外部状态: 随环境改变,不可共享,由客户端维护");
System.out.println("🔑 享元工厂: 管理对象池,确保对象正确共享");
System.out.println("🔑 单例工厂: 通常使用单例模式实现工厂");
System.out.println("\n=== 享元模式注意事项 ===");
System.out.println("⚠️ 线程安全: 多线程环境需要考虑同步问题");
System.out.println("⚠️ 状态分离: 正确区分内部状态和外部状态");
System.out.println("⚠️ 复杂度: 增加了系统复杂度,需权衡");
System.out.println("⚠️ 适用条件: 只有大量相似对象时才有优势");
}
}
Last updated
Was this helpful?