跳至正文
来两杯美式
返回

设计模式之享元模式:共享细粒度对象,降低内存占用

By 来两杯美式
发布于

这是 2020 年 6 月整理的设计模式专题第九篇。享元模式是”以共享换性能”的代表——大量相似对象重复创建很浪费内存,共享起来就省了。Java 的 Integer 缓存、字符串常量池、连接池,都是它的应用。

简单说明

享元模式(Flyweight Pattern):提供了减少对象的数量从而改善应用所需的对象结构的方式,运用共享技术有效地支持大量细粒度的对象。

内部状态与外部状态

享元模式最关键的概念是状态分离

状态含义示例
内部状态存储在享元对象内部,可共享、不随环境变化棋子的形状、颜色
外部状态由客户端传入,随场景变化,不可共享棋子的位置坐标

核心思想:把可共享的内部状态放进享元对象缓存复用;把不可共享的外部状态在使用时由客户端传入,不存入共享对象。

/**
 * 描述:享元接口
 */
public interface Chess {
    void play(int x, int y);   // x,y 是外部状态,由客户端传入
}

/**
 * 描述:具体享元:棋子(内部状态:颜色)
 */
public class ChessPiece implements Chess {
    private String color;      // 内部状态:可共享

    public ChessPiece(String color) {
        this.color = color;
    }

    @Override
    public void play(int x, int y) {
        System.out.println(color + "棋落在(" + x + "," + y + ")");
    }
}

/**
 * 描述:享元工厂:用 Map 缓存,复用对象
 */
public class ChessFactory {
    private static final Map<String, Chess> CHESS_MAP = new HashMap<>();

    public static Chess getChess(String color) {
        // 缓存中已有就直接复用,没有才创建
        Chess chess = CHESS_MAP.get(color);
        if (chess == null) {
            chess = new ChessPiece(color);
            CHESS_MAP.put(color, chess);
        }
        return chess;
    }
}

public class FlyweightTest {
    public static void main(String[] args) {
        // 一盘棋 32 颗棋子,但只有黑白 2 个享元对象,位置由外部传入
        Chess black1 = ChessFactory.getChess("");
        Chess black2 = ChessFactory.getChess("");
        System.out.println("black1 == black2 : " + (black1 == black2));  // true,同一个对象

        black1.play(1, 1);
        black2.play(2, 2);
    }
}

关键black1 == black2true——同样的”黑棋”对象被反复复用,只有位置(外部状态)在变。

优点与缺点

优点

缺点

实现要点

将对象创建后,用例如 Map 结构缓存起来,再用的时候直接从缓存容器中获取。例如各种连接池功能的实现。

public class ConnectionPool {
    private static final List<Connection> POOL = new LinkedList<>();
    // 初始化时创建固定数量连接放入池中
    // 取用:从池中借出;用完:归还到池中
}

现实中的应用

场景说明
字符串常量池相同字符串字面量复用同一个 String 对象
Integer 缓存Integer.valueOf(-128~127) 返回缓存对象
数据库连接池 / 线程池昂贵资源复用,避免反复创建销毁
字符/词法分析器大量细粒度 token 对象共享
RPC 连接复用相同目标的连接复用

适用场景

小结


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.软件设计原则:SOLID + KISS / YAGNI / LOD 全景
  2. 02.设计模式之原型模式,及深浅拷贝
  3. 03.设计模式之工厂模式:简单工厂、工厂方法与抽象工厂
  4. 04.设计模式之建造者模式:复杂对象的组装艺术
  5. 05.设计模式之适配器模式:让不兼容的接口协同工作
  6. 06.设计模式之桥接模式:抽象与实现分离,各自独立变化
  7. 07.设计模式之装饰者模式:动态增强,比继承更有弹性
  8. 08.设计模式之代理模式:静态代理与 JDK 动态代理
  9. 09.设计模式之外观模式:统一门面,简化子系统调用
  10. 10.设计模式之享元模式:共享细粒度对象,降低内存占用
  11. 11.设计模式之策略模式:算法家族,自由切换
  12. 12.设计模式之模板方法模式:固定骨架,可变步骤
  13. 13.设计模式之观察者模式:一对多依赖,状态变更自动通知
  14. 14.设计模式之责任链模式:请求逐级传递,动态组合处理者
  15. 15.设计模式之状态模式:状态变,行为变
  16. 16.设计模式之迭代器模式:不暴露内部实现,顺序访问集合

上一篇
DDD 复杂业务系统设计(总结):从领域到微服务,一张图看懂 DDD 落地全流程
下一篇
DDD 复杂业务系统设计(十):从战略到微服务,一张图跑通 DDD+中台+微服务