java23种设计模式-享元模式

发布于:2025-02-26 ⋅ 阅读:(101) ⋅ 点赞:(0)

享元模式(Flyweight Pattern)学习笔记

1. 模式定义

结构型设计模式,通过共享技术实现大量细粒度对象的复用,有效减少内存占用并提高性能。核心思想:分离内部状态(可共享)与外部状态(不可共享)

2. 适用场景

✅ 系统中存在大量相似对象

✅ 对象的大部分状态可以外部化

✅ 需要缓存池或对象池的应用

✅ 需要减少内存占用和提高性能的场景

3. 模式结构

creates
requests
FlyweightFactory
-pool: Map
+getFlyweight(key)
«interface»
Flyweight
+operation(extrinsicState)
ConcreteFlyweight
-intrinsicState
+operation(extrinsicState)
UnsharedConcreteFlyweight
-allState
+operation(extrinsicState)
Client
-flyweights: List
+addFlyweight()
+executeOperations()

4. 核心角色

角色 说明
Flyweight 抽象享元接口,定义操作接口
ConcreteFlyweight 具体享元类,包含内部状态(可共享)
UnsharedConcreteFlyweight 非共享具体享元类(可选)
FlyweightFactory 享元工厂类,管理享元对象池
Client 客户端,维护外部状态并调用享元对象

5. 状态说明

状态类型 说明
内部状态 存储在享元对象内部,可以被多个上下文共享的信息
外部状态 随上下文变化的信息,由客户端保存并在调用时传入

6. 代码示例

6.1 文字编辑器字符对象

// 抽象享元
interface Character {
    void display(int x, int y, String color);
}

// 具体享元
class ConcreteCharacter implements Character {
    private char symbol;  // 内部状态
    
    public ConcreteCharacter(char symbol) {
        this.symbol = symbol;
    }

    @Override
    public void display(int x, int y, String color) {  // 外部状态
        System.out.printf("显示字符 %c 在(%d,%d),颜色:%s%n", symbol, x, y, color);
    }
}

// 享元工厂
class CharacterFactory {
    private Map<Character, Character> pool = new HashMap<>();
    
    public Character getCharacter(char key) {
        if (!pool.containsKey(key)) {
            pool.put(key, new ConcreteCharacter(key));
        }
        return pool.get(key);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        CharacterFactory factory = new CharacterFactory();
        
        List<Character> document = new ArrayList<>();
        document.add(factory.getCharacter('H'));
        document.add(factory.getCharacter('e'));
        document.add(factory.getCharacter('l'));
        document.add(factory.getCharacter('l'));
        document.add(factory.getCharacter('o'));

        int x = 0;
        for (Character c : document) {
            c.display(x++, 0, "black");  // 传递外部状态
        }
    }
}

7. 模式变种

  1. 复合享元模式:将多个单纯享元组合成复合对象
  2. 线程级享元:结合ThreadLocal实现线程级共享
  3. 带缓存清理机制:实现LRU缓存策略管理享元对象

8. 优缺点分析

✔️ 优点

  • 极大减少内存中对象的数量
  • 外部状态相对独立,增强程序灵活性
  • 享元对象可被不同场景复用

缺点

  • 增加系统复杂度(需要分离内外状态)
  • 需要额外关注线程安全问题
  • 可能影响程序执行效率(查找/计算外部状态)

9. 相关模式对比

模式 目的 关键区别
单例模式 控制实例数量 享元可能有多个不同实例
原型模式 对象克隆 享元强调共享已有对象
对象池模式 重用对象 对象池管理临时对象,享元管理永久对象

10. 实际应用案例

  • Java String常量池(-128~127的Integer缓存)
  • 棋牌游戏的棋子对象管理
  • 文档编辑器中的字符/段落格式
  • 图形编辑器中的图形对象
  • 数据库连接池

11. 最佳实践建议

  1. 严格区分内部状态和外部状态
  2. 使用不可变对象作为享元对象
  3. 对享元工厂实现缓存淘汰策略(LRU)
  4. 考虑使用WeakReference管理享元池
  5. 外部状态参数尽量使用基本类型或不可变对象
  6. 多线程环境下需要同步处理享元工厂

🧩 记忆技巧:把享元模式想象成"共享单车"系统,单车(内部状态)是共享的,用户(外部状态)各自的使用位置不同。


网站公告

今日签到

点亮在社区的每一天
去签到