简千叶 发表于 2025-6-6 14:49:16

「全网最细 + 实战源码案例」设计模式——享元模式


核心思想


[*]享元模式(Flyweight Pattern)是一种结构型设计模式,主要用于减少程序中大量对象的内存消耗。该模式通过共享相同的数据来有效减少内存的使用,适用于对象非常多且可以共享一部分状态的场景。
[*]核心:将对象的内部状态和外部状态分离:


[*]

[*]内部状态:存储在享元对象内部的、不会改变的状态,通常是可以共享的。
[*]外部状态:依赖于环境且变化的状态,不可共享。

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/aef7854a30f643169b2dd63880c87d8b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575417&x-orig-sign=P4Ob66%2FkbJxd8HZjGXkk5mySmkA%3D​
编辑
结构

1. Flyweight(享元角色)


[*]声明享元对象的接口,通常是不可变的。
2. ConcretFlyweight(具体享元角色)


[*]实现 Flyweight 接口,存储共享状态。
3. UnsharedConcreteFlyweight(非共享具体享元角色)


[*]非共享的享元对象,一般不是由享元工厂创建。
4. FlyweightFactory(享元工厂)


[*]用来管理享元对象的工厂类,确保共享对象的唯一性。
https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/140c4670937347a2b89a1e184ef4df97~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575417&x-orig-sign=bOHynQzn1BbrkvFrqayq6yZRbQ4%3D​
编辑
适用场景


[*]存在大量相似对象。
[*]对象状态可分为内部、外部状态。
[*]节省内存,避免重复创建对象。
优缺点

优点:


[*]节省内存:避免重复创建相似对象。
[*]提高性能:减少重复创建对象的开销。
缺点:


[*]增加复杂性:享元模式、工厂类的设计。
实现步骤


[*]将需要改写为享元的类成员变量拆分为两个部分:

[*]
[*]内在状态: 包含不变的、 可在许多对象中重复使用的数据的成员变量。
[*]外在状态: 包含每个对象各自不同的情景数据的成员变量


[*]保留类中表示内在状态的成员变量, 并将其属性设置为不可修改。 这些变量仅可在构造函数中获得初始数值。
[*]找到所有使用外在状态成员变量的方法, 为在方法中所用的每个成员变量新建一个参数, 并使用该参数代替成员变量。
[*]你可以有选择地创建工厂类来管理享元缓存池, 它负责在新建享元时检查已有的享元。 如果选择使用工厂, 客户端就只能通过工厂来请求享元, 它们需要将享元的内在状态作为参数传递给工厂。
[*]客户端必须存储和计算外在状态 (情景) 的数值, 因为只有这样才能调用享元对象的方法。 为了使用方便, 外在状态和引用享元的成员变量可以移动到单独的情景类中。
示例

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/a1b10acb9f6743a8ae76f013461fb2b3~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575418&x-orig-sign=d0UPTCawoAqbLcH62WBMltyZebM%3D​
编辑
https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/6e118e2d47694082aa27d2f775f9023c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575417&x-orig-sign=EJbnzmgAuXcfkqk8EvADiDNkCBQ%3D​
编辑
// 享元角色
public abstract class AbstractBox {

    // 获取图形
    public abstract String getShape();

    // 显示图形及颜色
    public void display(String color){
      System.out.println("方块:" + getShape() + ",颜色:" + color);
    }
}

// 具体享元角色——I
public class IBox extends AbstractBox{
    @Override
    public String getShape() {
      return "I";
    }
}

// 具体享元角色——L
public class LBox extends AbstractBox{
    @Override
    public String getShape() {
      return "L";
    }
}

// 具体享元角色——O
public class OBox extends AbstractBox{
    @Override
    public String getShape() {
      return "O";
    }
}

// 享元工厂(静态内部类单例方式)
public class BoxFactory {

    // 享元对象池
    private Map<String, AbstractBox> boxes;

    // 私有化构造器
    private BoxFactory() {
      boxes = new HashMap<>();
      boxes.put("L", new LBox());
      boxes.put("I", new IBox());
      boxes.put("O", new OBox());
    }

    // 获取享元对象
    public AbstractBox getBox(String type) {
      return boxes.get(type);
    }

    // 创建静态内部类
    private static class SingletonHolder {
      private static final BoxFactory INSTANCE = new BoxFactory();
    }

    // 获取享元工厂实例
    public static BoxFactory getInstance() {
      return SingletonHolder.INSTANCE;
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {

      // 1.获取享元工厂
      BoxFactory boxFactory = BoxFactory.getInstance();

      // 2.获取享元对象
      AbstractBox box1 = boxFactory.getBox("L");
      AbstractBox box2 = boxFactory.getBox("I");
      AbstractBox box3 = boxFactory.getBox("O");
      AbstractBox box4 = boxFactory.getBox("O");

      // 3.获取非享元对象并显示
      box1.display("red");
      box2.display("blue");
      box3.display("green");
      box4.display("yellow");

      // 4.验证享元对象是否共享
      System.out.println(box3 == box4);

    }
}
在源码中的应用

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/5625be2092b0495fb3cf29e08a2ee607~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575417&x-orig-sign=w9SSHJCyIghvKlTfTIHDtBic1Y0%3D​
编辑
https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/436e340daa48461f89125fd9ea7d17c7~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575417&x-orig-sign=uJARlhSQ4iD%2BFPYhdlo%2FTn8N45o%3D​
编辑
https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/ece99e220b8545e8811d2f6989dbf64b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575417&x-orig-sign=lM1BLmRliCQXUD5fLzPxrHvQ%2Fgc%3D​
编辑
https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/c6b218ffeec948f9bb7a401e82a6c111~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2xhY2tDbGltYg==:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiODY5MDc1Mjk1NDEwMDA5In0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1738575417&x-orig-sign=XS4%2BnLmn92hCs6BV4WUZNmyaP3M%3D​
编辑
与其他模式的关系


[*]你可以使用享元模式实现组合模式树的共享叶节点以节省内存。
[*]享元展示了如何生成大量的小型对象, 外观模式则展示了如何用一个对象来代表整个子系统。
[*]如果你能将对象的所有共享状态简化为一个享元对象, 那么享元就和单例模式类似了。 但这两个模式有两个根本性的不同。


[*]

[*]只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同。
[*]单例对象可以是可变的。 享元对象是不可变的。



来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 「全网最细 + 实战源码案例」设计模式——享元模式