设计模式之享元模式

news2024/9/21 2:47:38

Flyweight design pattern

享元模式的概念、享元模式的结构、享元模式的优缺点、享元模式的使用场景、享元模式的实现示例、享元模式的源码分析


1、享元模式的概念

  享元模式,即运用共享技术来有效的支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似对象的开销,从而提高系统资源的利用率。

  享元模式中存在以下两种状态:

  • 内部状态:即不会随着环境的改变而改变的可共享状态。
  • 外部状态:即随着环境的改变而改变的不可共享状态。享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。

2、享元模式的结构

  • 抽象享元角色:定义向外界提供内部状态的抽象方法,同时声明外界设置外部状态的的方法。
  • 具体享元角色:继承自抽象享元角色,实现向外界提供内部状态的抽象方法。
  • 飞享元角色:即外部状态,即不可共享的部分,可以参数的形式注入到享元对象中去。
  • 享元工厂:负责创建和管理享元对象。当客户对象请求一个享元对象时,享元工厂检查系统中是否已存在符合要求的享元对象,若存在则返回给用户,若不存在则创建一个新的享元对象返回给客户并维护到系统中。因为系统中享元角色的创建和管理只需一个角色,故此工厂可设计位单例。

flyweight-class

3、享元模式的优缺点

  • 优点:
    • 减少相似对象的创建,降低系统内存开销,提高效率。
  • 缺点:
    • 一定程度上增加了系统的复杂度,需要分离出内部状态和外部状态,内部状态不变,外部状态可变,容易造成系统混乱。

4、享元模式的使用场景

  • 当系统中存在大量相同或相似的对象时,避免造成系统内存大量耗费。
  • 当对象的大部分状态可外部化时,可将这些外部状态传入对象中。
  • 在使用享元模式时,需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,故,应在需要多次重复使用享元对象时才值得使用享元模式。

5、享元模式的实现示例

抽象享元角色:

public abstract class Hero {

    /**
     * 向外界提供不可变内部状态(可共享)
     * @return
     */
    public abstract String getName();

    /**
     * 外界设置可变外部状态(不可共享)
     * @param equipment
     */
    public void equipment(String equipment) {
        System.out.println("英雄名称 " + this.getName() + " 装备 " + equipment);
    }
}

具体享元角色:

public class ZedHero extends Hero {

    @Override
    public String getName() {
        return "影流之主";
    }
}

具体享元角色:

public class FizzHero extends Hero {

    @Override
    public String getName() {
        return "潮汐海灵";
    }
}

具体享元角色:

public class AhriHero extends Hero {

    @Override
    public String getName() {
        return "九尾妖狐";
    }
}

享元工厂:

public class FlyWeightFactory {

    private static Map<String, Hero> map;

    private static FlyWeightFactory factory;

    private FlyWeightFactory() {
        map = new HashMap<>(3);
        map.put("zed", new ZedHero());
        map.put("fizz", new FizzHero());
        map.put("ahri", new AhriHero());
    }

    public static FlyWeightFactory getInstance() {
        if (factory == null) {
            synchronized (FlyWeightFactory.class) {
                if (factory == null) {
                    factory = new FlyWeightFactory();
                }
            }
        }
        return factory;
    }

    public Hero getHero(String name) {
        return map.get(name);
    }
}

测试:

public class FlyWeightTest {

    public static void main(String[] args) {
        Hero zed = FlyWeightFactory.getInstance().getHero("zed");
        zed.equipment("德拉克撒的慕刃");

        Hero fizz = FlyWeightFactory.getInstance().getHero("fizz");
        fizz.equipment("卢登的激荡");

        Hero zed1 = FlyWeightFactory.getInstance().getHero("zed");
        zed1.equipment("赛瑞尔达的怨恨");

        System.out.println(zed == zed1);
    }
}

测试结果:

英雄名称 影流之主 装备 德拉克撒的慕刃
英雄名称 潮汐海灵 装备 卢登的激荡
英雄名称 影流之主 装备 赛瑞尔达的怨恨
true

6、享元模式的源码分析

  jdk 的 Integer 类的设计就使用到了享元模式。

public class IntegerTest {

    public static void main(String[] args) {
        Integer a = 127;
        Integer b = 127;

        Integer c = 128;
        Integer d = 128;

        System.out.println(a == b);
        System.out.println(c == d);
    }
}
// 测试结果
true
false

  从测试结果结合 Integer 源码可知,Integer 对 -128 ~ 127 之间的数进行了缓存,所以对象 a、b 实际上是同一个对象,因为其被换存在内存中了,而对象 c、d 则是两个不同的对象,因为其没有被缓存。

  Integer a = 127; 这段代码反编译后实际上会变成 Integer a = Integer.valueOf((int) 127); 也就是实际上是调用了 Integer 的 valueOf() 方法。

@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
  if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
  return new Integer(i);
}
private static class IntegerCache {
  static final int low = -128;
  static final int high;
  static final Integer cache[];

  static {
    // high value may be configured by property
    int h = 127;
    String integerCacheHighPropValue =
      VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    if (integerCacheHighPropValue != null) {
      try {
        int i = parseInt(integerCacheHighPropValue);
        i = Math.max(i, 127);
        // Maximum array size is Integer.MAX_VALUE
        h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
      } catch( NumberFormatException nfe) {
        // If the property cannot be parsed into an int, ignore it.
      }
    }
    high = h;

    cache = new Integer[(high - low) + 1];
    int j = low;
    for(int k = 0; k < cache.length; k++)
      cache[k] = new Integer(j++);

    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
  }

  private IntegerCache() {}
}

  从 Integer.valueOf() 的源码可知,Integer 内部用了一个 IntegerCache 内部类来维护要被缓存的数值范围即被缓存的对象数组,可以看到在 low(-128) 到 high(127)之间的数值被缓存在 cache[] 中了。在调用 Integer.valueOf() 方法时,如果传入的值在 low 和 high 之间,则之间返回数组中的元素,若不在则创建一个新的对象返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/99531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于nodejs博客系统的设计与实现.rar(论文+源码+ppt文档+视频录制)

第一章绪论 3 1.1项目开发的背景和意义 3 1.2国内外研究的现状 4 1.3研究的主要内容 4 第2章系统相关技术介绍 5 2.1 B/S结构技术介绍 5 2.2nodejs技术介绍 6 2.3mysql数据库 7 第三章系统分析 8 3.1可行性分析 8 3.2功能需求分析 8 3.2.1登录模块需求分析 9 3.2.2分类博客模块…

NetSuite 如何统一用户的时区

在NetSuie的原始设置中&#xff0c;用户可以设置自己的时区&#xff0c;这在单一国家的环境中实际上是个缺点。例如&#xff0c;有些客户并没有注意到自己的时区是否是本国时区&#xff0c;所以在查看系统日志时&#xff0c;发现时间不对头&#xff0c;产生了困扰。所以&#x…

操作系统,计算机网络,数据库刷题笔记13

操作系统&#xff0c;计算机网络&#xff0c;数据库刷题笔记13 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xf…

SpringBoot3.0自定义stater整合chatGPT49种应用场景代码已开源

导读 导读 | 12月总体来说互联网的技术圈是非常热闹的&#xff0c;chatGPT爆火&#xff0c;SpringBoot3.0发布等重磅陆消息续进入大家的视线&#xff0c;而本文作者将以技术整合的角度&#xff0c;带大家把最火的两个技术整合在一起。读完本文&#xff0c;你将熟悉SpringBoot3…

我的java学习

犹豫了很久&#xff0c;还是打算简述一下自己学java 的历程&#xff0c;花了些时间&#xff0c;但结果不赖 文章目录从0的开始开始加速过度项目学习懵懂的进入项目进入综合项目学习第二次学习开始从0的开始 没有计算机基础&#xff0c;英语也非常糟糕。 起初也时常在想&#x…

Java+MySQL基于SSM的高校科研仪器共享平台

随着在校学生人数的不断增加,学生的数量也在不断的增加,同时面临的就是如何更加方便快捷和高效的管理高校科研仪器的问题,传统模式的科研仪器管理明显已经不能够满足当下的需求,于是我们提出了高校科研仪器共享平台的设计与开发。 本课题是一个基于SSM的管理系统,本高校科研仪器…

架构设计(六):引入消息队列

架构设计&#xff08;六&#xff09;&#xff1a;引入消息队列 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;架构设计&#xff08;六&#xff09;&#xff1a;引入消息队列 CSDN&#xff1a;架构设计&#xff08;六&#xff09;&#xff1a;引入消息队列…

【LeetCode】1703. 得到连续 K 个 1 的最少相邻交换次数

题目描述 给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1 。每一次移动&#xff0c;你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包含 k 个 连续 1 的 最少 交换次数。 示例 1&#xff1a; 输入&#xff1a;nums [1,0,0,1,0,1], k 2 输出&#xf…

入门:镜像结构介绍

前面我们了解了Docker的相关基本操作&#xff0c;实际上容器的基石就是镜像&#xff0c;有了镜像才能创建对应的容器实例&#xff0c;那么我们就先从镜像的基本结构开始说起&#xff0c;我们来看看镜像到底是个什么样的存在。 我们在打包项目时&#xff0c;实际上往往需要一个基…

C++PrimerPlus 第八章 函数探幽-8.1 C++内联函数

目录 8.1 C内联函数 8.1 C内联函数 内联函数是C为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式&#xff0c;而在于C编译器如何将它们组合到程序中。要了解内联函数与常规函数之间的区别&#xff0c;必须深入到程序内部。 编译过程的最终…

微机原理与接口技术笔记

文章目录前言储存系统与技术材料高速储存器缓冲储存器&#xff08;Cache&#xff09;材料&#xff0c;局部性&#xff0c;访问方式Cache全相联映射Cache交换与一致性单核CPU一致性处理多核CPU的MESI协议主储存器&#xff08;内存&#xff09;主要技术指标容量带宽内存模组与内存…

牛客题霸sql入门篇之条件查询(四)之高级查询

牛客题霸sql入门篇之条件查询(四)之高级查询 4 计算函数 4.1 查询GPA最高值 4.1.1 题目内容 4.1.2 示例代码 SELECT gpa FROM user_profile WHERE university复旦大学 ORDER BY gpa desc limit 1; -- LIMIT 初始位置&#xff0c;记录数 一个参数就是记录数4.1.3 运行结果 4…

Python Flask构建微信小程序订餐系统 (四)

🔥 创建微信小程序 🔥 微信开发者工具下载 并完成安装 在PyCharm 工具里面 order目录下面 创建mina 文件夹 通过微信小程序开发工具创建微信小程序工程 获取微信小程序ID

数据挖掘Java——PageRank算法的实现

一、PageRank算法的前置知识 PageRank算法&#xff1a;计算每一个网页的PageRank值&#xff0c;然后根据这个值的大小对网页的重要性进行排序。 从用户角度来看&#xff0c;一个网站就是若干页面组成的集合。然而&#xff0c;对于网站的设计者来说&#xff0c;这些页面是经过…

嵌入式系统开发笔记109:多个LED的闪烁控制

文章目录前言一、一般思路1、LED0 100ms闪烁&#xff0c;LED1 200ms闪烁2、LED0 100ms闪烁&#xff0c;LED1 300ms闪烁3、LED0 200ms闪烁&#xff0c;LED1 600ms闪烁二、通过循环变量实现1、LED0 500ms闪烁&#xff0c;LED1 700ms闪烁2、LED0 15ms闪烁&#xff0c;LED1 7ms闪烁…

Java——LRUCache

概念 简单来说&#xff0c;由于我们的空间是有限的&#xff0c;所以发明了这个数据结构&#xff0c;当我们的空间不够添加新的元素时&#xff0c;就会删除最近最少使用的元素。 其底层逻辑通过哈希表和链表共同实现。哈希表中存储链表的每一个元素&#xff0c;方便进行元素的…

Mysql分布式锁(三)悲观锁实现并发

在前面的方法中&#xff0c;一条sql语句中仍然存在着很多问题&#xff0c;于是我们可以用悲观锁来代替解决。 假设我们不用一条sql&#xff0c;仍然用先查询&#xff0c;判断&#xff0c;最后更新来实现业务。 文章目录悲观锁 select...for update1. 不加悲观锁1) 两个机器连接…

因果推断2--深度模型介绍(个人笔记)

目录 一、方法介绍 1.1TarNet 1.1.1TarNet 1.1.2网络结构 1.1.3counterfactual loss 1.1.4代码实现 1.2Dragonet 1.3DRNet 1.4VCNet VCNET AND FUNCTIONAL TARGETED REGULARIZATION FOR LEARNING CAUSAL EFFECTS OF CONTINUOUS TREATMENTS 二、待补充 一、方法介绍 …

AcWing 第82场周赛

AcWing 第82场周赛 竞赛 - AcWing B 4783. 多米诺骨牌 - AcWing题库 模拟题&#xff0c;考察代码描述问题的能力。 由题意所给的数学形式化定义中看出&#xff0c;所给的骨牌初始序列 L 和 R 的顺序一定是相互交错的&#xff0c;即 ...LRLRLRLR... 所以&#xff0c;一旦遇到…

KNN算法 搜索最优超参数:n_neighbors/weights/p

目录 一&#xff1a;遍历参数 超参调优测试 二&#xff1a;网格模型 超参调优测试 三&#xff1a;模型保存 四&#xff1a;模型使用 一&#xff1a;遍历参数 超参调优测试 1.1 超参调试&#xff0c;找到模型最优解[仅做测试&#xff0c;得出最优&#xff1a;n_neighbors, …