Java设计模式之享元模式详解

Java设计模式之享元模式详解


一、享元模式核心思想

核心目标通过共享技术高效支持大量细粒度对象,减少内存消耗。将对象分为内部状态(共享)外部状态(不可共享),如同活字印刷术重复使用字模。


二、享元模式类图(Mermaid)

创建/存储
FlyweightFactory
-pool: Map
+getFlyweight(key: String) : Flyweight
«interface»
Flyweight
+operation(extrinsicState: String)
ConcreteFlyweight
-intrinsicState: String
+operation(extrinsicState: String)
UnsharedConcreteFlyweight
-allState: String
+operation(extrinsicState: String)

三、代码实现示例

1. 围棋棋子共享场景

// 抽象享元
interface ChessPiece {
    void draw(int x, int y);  // 外部状态:坐标
}

// 具体享元(内部状态:颜色)
class BlackChess implements ChessPiece {
    private final String color = "黑色";  // 内部状态
    
    public void draw(int x, int y) {
        System.out.printf("%s棋子落子(%d,%d)\n", color, x, y);
    }
}

// 享元工厂
class ChessFactory {
    private static final Map<String, ChessPiece> pool = new HashMap<>();
    
    public static ChessPiece getChess(String color) {
        return pool.computeIfAbsent(color, c -> {
            if ("黑色".equals(c)) return new BlackChess();
            if ("白色".equals(c)) return new WhiteChess();
            throw new IllegalArgumentException();
        });
    }
}

// 客户端调用
ChessPiece black1 = ChessFactory.getChess("黑色");
ChessPiece black2 = ChessFactory.getChess("黑色");  // 复用对象
black1.draw(10, 20);
black2.draw(15, 25); 

四、模式优缺点分析

✅ 优势

  • 内存优化:减少重复对象的创建(如10万个字符只需26个字母对象)
  • 性能提升:降低垃圾回收压力
  • 集中管理:通过工厂统一控制共享对象

❌ 缺点

  • 增加系统复杂度:需要分离内部/外部状态
  • 线程安全风险:共享对象需设计为不可变
  • 调试困难:对象复用可能导致逻辑追踪困难

五、典型应用场景

  1. 文本编辑器:字符对象池(ASCII共128个字符)
  2. 游戏开发:粒子系统(火花、雨滴等特效复用)
  3. 数据库连接池:复用已建立的连接
  4. GUI系统:图标/按钮样式共享
  5. 棋牌游戏:麻将/扑克牌面图案复用

六、Mermaid序列图(对象获取流程)

Client Factory Flyweight getFlyweight("A") 返回现有对象 创建新对象 返回新对象 alt [对象已存在] [对象不存在] Client Factory Flyweight

七、享元模式 vs 其他模式

对比模式核心区别
单例模式控制实例数量而非对象共享
对象池模式管理临时对象复用,享元对象永久存在
代理模式控制访问而非共享对象

八、内部状态 vs 外部状态

状态类型特点示例
内部状态对象固有属性,可共享棋子的颜色、字符的Unicode
外部状态对象上下文信息,不可共享棋子的位置、字符的坐标

九、实际框架应用案例

1. Java String常量池

String s1 = "享元";          // 加入常量池
String s2 = "享元";          // 复用常量池对象
String s3 = new String("享元"); // 新建对象

System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false

2. Java Integer缓存池

Integer i1 = 127;  // 使用缓存
Integer i2 = 127;
Integer i3 = 128;  // 新建对象
Integer i4 = 128;

System.out.println(i1 == i2); // true
System.out.println(i3 == i4); // false

十、常见问题解答

Q1:如何保证享元对象的线程安全?

  • 设计为不可变对象:所有属性用final修饰
  • 使用线程安全集合:如ConcurrentHashMap管理对象池

Q2:如何处理需要不同的享元对象?

通过组合方式扩展:

组合
Style
+font: String
+size: int
Character
-char: char
-style: Style

Q3:享元模式与缓存有何区别?

  • 缓存:临时存储数据,可能被清除
  • 享元:永久存储对象,生命周期与应用一致

掌握享元模式,能有效优化内存密集型应用的性能。记住:不是所有重复对象都适合共享,需权衡内存节省与代码复杂度!

如果文章对你有帮助,请帮忙点个关注吧,谢谢啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

季鸢

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值