lizema lizema
首页
  • js

    • js
  • Git相关

    • 《Git》
  • 设计模式

    • 设计模式
  • java
  • jdk
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • HTML
  • CSS
  • 学习方法
  • 敏捷开发心得
  • 心情杂货
  • 实用技巧
  • GPT相关
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

malize

各自努力,顶峰相见。
首页
  • js

    • js
  • Git相关

    • 《Git》
  • 设计模式

    • 设计模式
  • java
  • jdk
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • HTML
  • CSS
  • 学习方法
  • 敏捷开发心得
  • 心情杂货
  • 实用技巧
  • GPT相关
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 工作中用到的设计模式
  • 享元模式
    • 单例模式
    • 原型模式
    • 备忘录模式
    • 外观模式
    • 工厂方法模式
    • 模板方法模式
    • 策略模式
    • 装饰模式
    • 访问者模式
    • 责任链模式
    • 适配器模式
    • 中介者模式
    • 设计模式
    malize
    2020-11-18
    目录

    享元模式

    # 享元模式

    # 一、享元模式

    1. 原理:享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。

    2. 优缺点

      1. 1 优点
      • 减少内存使用: 通过共享相似对象的公共部分,可以减少内存使用量,特别是当系统中存在大量相似对象时,这种节省可以显著提高性能和减少资源消耗。
      • 提高性能: 由于减少了对象的数量,因此在创建和销毁对象时的开销也相应减少,可以提高系统的性能。
      • 提高可维护性: 享元模式将对象的状态分为内部状态和外部状态,内部状态是可以共享的,外部状态是不可共享的。这种区分有助于更好地管理对象状态,使得系统更易于维护。
      • 支持大规模对象: 享元模式适用于需要大量相似对象的场景,例如图形编辑器中的图元对象,文档编辑器中的字符对象等。
      1. 2 缺点
      • 复杂性增加: 享元模式引入了共享对象池和状态管理机制,这增加了系统的复杂性,使得代码变得更加难以理解和维护。
      • 可能引入线程安全问题: 如果享元对象被多个线程同时访问和修改,可能会引入线程安全问题,需要额外的同步机制来保证对象的状态不被破坏。
      • 可能引入性能问题: 尽管享元模式可以减少内存使用和对象数量,但在某些情况下,共享对象的创建和管理可能会引入额外的性能开销,特别是在对象的状态转换复杂或者需要频繁修改状态时。
      • 对外部状态的管理: 在享元模式中,需要额外的机制来管理外部状态,例如在享元对象外部维护状态信息的数据结构,这增加了系统的复杂性和开发成本。
    3. 适用场景

      • 大量相似对象: 当系统中存在大量相似对象,并且这些对象的区别主要在于它们的内部状态时,可以使用享元模式来共享这些相似对象的内部状态,减少内存消耗。
      • 频繁创建和销毁对象: 如果系统中频繁创建和销毁对象,而且创建对象的开销比较大,可以使用享元模式来缓存已经创建的对象,避免重复创建,提高系统性能。
      • 对象数量巨大: 在需要管理大量对象的系统中,例如图形编辑器、文档编辑器等,通过享元模式可以有效地减少对象的数量,减少系统的内存消耗和资源占用。
      • 对象的状态可以分为内部状态和外部状态: 如果对象的状态可以分为内部状态和外部状态,并且内部状态可以共享,外部状态可以通过参数传递的方式进行管理,那么可以使用享元模式来提高系统的效率。
      • 需要缓存对象以提高性能: 在需要缓存对象以提高系统性能的场景中,可以使用享元模式来缓存对象,避免重复创建和销毁对象,提高系统的响应速度。

    # 二、享元模式基本代码

    1. 享元接口

      interface Shape {
          void draw();
      }
      
      1
      2
      3
    2. 具体享元类

      class Circle implements Shape {
          private String color;
      
          public Circle(String color) {
              this.color = color;
          }
      
          @Override
          public void draw() {
              System.out.println("Drawing Circle with color: " + color);
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
    3. 享元工厂类

      class ShapeFactory {
          private static final HashMap<String, Shape> circleMap = new HashMap<>();
      
          // 获取圆形对象
          public static Shape getCircle(String color) {
              Circle circle = (Circle) circleMap.get(color);
      
              // 如果不存在该颜色的圆形,则创建一个新的圆形对象并放入享元池中
              if (circle == null) {
                  circle = new Circle(color);
                  circleMap.put(color, circle);
                  System.out.println("Creating new Circle with color: " + color);
              }
              
              return circle;
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
    4. 客户端

      public class Main {
          private static final String[] colors = { "Red", "Green", "Blue", "Yellow", "Black" };
      
          public static void main(String[] args) {
              // 模拟绘制不同颜色的圆形
              for (int i = 0; i < 10; ++i) {
                  String color = colors[(int) (Math.random() * colors.length)];
                  Shape circle = ShapeFactory.getCircle(color);
                  circle.draw();
              }
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

    # 三、实现方式

    1. 将需要改写为享元的类成员变量拆分为两个部分:
      • 内在状态: 包含不变的、 可在许多对象中重复使用的数据的成员变量。
      • 外在状态: 包含每个对象各自不同的情景数据的成员变量
    2. 保留类中表示内在状态的成员变量, 并将其属性设置为不可修改。 这些变量仅可在构造函数中获得初始数值。
    3. 找到所有使用外在状态成员变量的方法, 为在方法中所用的每个成员变量新建一个参数, 并使用该参数代替成员变量。
    4. 你可以有选择地创建工厂类来管理享元缓存池, 它负责在新建享元时检查已有的享元。 如果选择使用工厂, 客户端就只能通过工厂来请求享元, 它们需要将享元的内在状态作为参数传递给工厂。
    5. 客户端必须存储和计算外在状态 (情景) 的数值, 因为只有这样才能调用享元对象的方法。 为了使用方便, 外在状态和引用享元的成员变量可以移动到单独的情景类中。
    编辑 (opens new window)
    #重学Java设计模式
    工作中用到的设计模式
    单例模式

    ← 工作中用到的设计模式 单例模式→

    最近更新
    01
    其他
    02
    其他
    03
    名人总结
    08-27
    更多文章>
    Theme by Vdoing
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式