• 设计模式之享元模式(结构型)


    1、享元模式介绍

    享元模式(Flyweight),主要用来减少创建对象的数量,以减少内存占用和提高性能。运用共享技术有效的支持持大量细粒度的对象。

    • flyweight 是轻量级的意思,指拳击比赛中的特轻量级拳击手。这个设计模式的作用就是为了将对象变,也就是对象使用的内存大小。一般情况下需要大量对象使用 new 进行创建,会消耗大量内存。
    • 享元模式中可以共享的内容称为内部状态,需要外部环境来设置的不能共享的内容称为外部状态。这两种状态是相互独立的,使用 flyweight 模式将一个对象的状态分为内部状态和外部状态,内部状态保持不变,共享不变的部分以达到减少内存占用的目的
    • 支持大量细粒度对象是因为在实际程序中,能够共享的内部状态比较有限,所以享元对象一般都比较小,包含的内部状态较少,所以称之为细粒度对象

    2、享元模式结构

    在这里插入图片描述
    享元模式角色:

    • Flyweight:享元接口,定义具体享元角色需要实现的方法,通过接口传入外部状态

      /**
       * 享元接口
       */
      public interface Flyweight {
      
          /**
           * 可以将外部状态作为参数传入方法,但不能改变方法的内部状态
           */
          void operator(String extrinsicStatus);
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • ConcreteFlyweight:具体享元对象,可共享内部状态,内部状态在创建时赋予,对象创建之后不再更改,外部状态使用参数传入

      /**
       * 具体享元对象
       */
      public class ConcreteFlyweight implements Flyweight {
      
          /**
           * 内部状态
           */
          private String internalStatus = null;
      
          public ConcreteFlyweight(String internalStatus) {
              this.internalStatus = internalStatus;
          }
      
          public ConcreteFlyweight() {
          }
      
          @Override
          public void operator(String extrinsicStatus) {
              System.out.println("internalStatus = " + this.internalStatus);
              System.out.println("extrinsicStatus = " + extrinsicStatus);
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    • UnsharedConcreteFlyweight:不需要共享的 Flyweight 子类,并不是所有的享元对象都可以共享,非共享的享元对象通常是享元对象的组合对象

      /**
       * 不共享的享元对象
       */
      public class UnsharedConcreteFlyweight implements Flyweight {
      
          @Override
          public void operator(String extrinsicStatus) {
              System.out.println("不共享的 extrinsicStatus = " + extrinsicStatus);
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • FlyweightFactory:享元工厂角色,负责创建和管理享元角色

      import java.util.HashMap;
      import java.util.Map;
      
      /**
       * 享元工厂
       */
      public class FlyweightFactory {
      
          private Map<String, Flyweight> maps = new HashMap<>();
      
          /**
           * 单例
           */
          private static FlyweightFactory instance = new FlyweightFactory();
      
          public static FlyweightFactory getInstance() {
              return instance;
          }
      
          /**
           * 根据 key 获取享元对象
           */
          public Flyweight getFlyweight(String key) {
              // 先从缓存中获取对象,对象不存在则创建对象放入容器中
              if (!maps.containsKey(key)) {
                  maps.put(key, new ConcreteFlyweight());
              }
              return maps.get(key);
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
    • 调用方

      public class FlyweightClient {
      
          public static void main(String[] args) {
              FlyweightFactory factory = FlyweightFactory.getInstance();
              Flyweight flyweightA = factory.getFlyweight("A");
              flyweightA.operator("A");
      
              Flyweight flyweightB = factory.getFlyweight("B");
              flyweightB.operator("B");
      
              UnsharedConcreteFlyweight unsharedConcreteFlyweight = new UnsharedConcreteFlyweight();
              unsharedConcreteFlyweight.operator("C");
      		// internalStatus = null
      		// extrinsicStatus = A
      		// internalStatus = null
      		// extrinsicStatus = B
      		// 不共享的 extrinsicStatus = C
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

    3、享元模式使用场景

    • 程序使用了大量的对象,这些大量的对象对内存的压力会比较大的时候可以考虑使用
    • 对象的大部分状态是外部状态的话,删除对象的外部状态,可以用相对较少的共享对象取代多组对象的话,可以使用共享模式。

    比如下棋游戏,一盘棋局可以下很多棋子,常规思维的话每个棋子都是一个对象,每局都会产生很多对象。使用 flyweight 模式的话,棋子的颜色一般是比较少而且不变的,颜色可以作为内部状态,棋子的区别在于它们的位置不同,棋子的坐标可以作为外部状态,这样的话棋子对象最多可以减少到两个实例。

    字符串 String 就运用了 flyweight,创建相同的字符串时,会将后创建的字符串的引用指向先创建的字符串,实现字符串再内存中的共享

    4、享元模式优缺点

    1. 享元模式可以有效的支持大量细粒度的对象
    2. 使用享元模式需要维护一个记录了系统已有的所有享元的容器,而且为了使对象共享,将一些状态外部化,程序的逻辑可能会变得复杂。最好在足够多的对象实例可供共享的时候才使用享元模式
  • 相关阅读:
    色氨酸乙酯双三氟甲基磺酰亚胺[TrpC2][Tf2N]离子液体
    (附源码)php投票系统 毕业设计 121500
    云小课|云小课带你玩转可视化分析ELB日志
    VUE3写后台管理(3)
    dubbo之配置文件
    Java-对象的构造及初始化
    java-net-php-python-ssm儿童演出礼服租赁网站计算机毕业设计程序
    SpringBoot学习笔记(4)——B站动力节点
    STC8H开发(十六): GPIO驱动XL2400无线模块
    【TA-霜狼_may-《百人计划》】美术2.7 Metallic 与 Speculer流程
  • 原文地址:https://blog.csdn.net/qq_53316135/article/details/127660526