结构型(三) - 享元模式

news2024/12/24 9:13:58

一、概念

享元模式(Flyweight Pattern):所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。

优点:可以极大地减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。

缺点:享元对象会一直被享元工厂类引用,不利于JVM互收,除非经过线上验证,利用享元模式真的可以大大节省内存,否则,就不要过度使用这个模式。

使用场景:我们在需要创建大量(例如10^5)的相似的对象时,使用享元模式,把不可变的对象单独抽出来,进行共享可以减少内存消耗。不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段),提取出来设计成享元,让这些大量相似对象引用这些享元。

二、实现

虽然我不玩游戏,但是这里举一个游戏的例子,一般比较火的游戏会有比较大的访问量。比如某一个游戏,游戏人物都可以选武器,游戏中的武器就那么几种,比如无影剑。所有玩家都可以选择这个武器,由于这个武器一旦上线一般不会改动,它内部的杀伤力等配置都是固定的,所以没必要为每一个玩家新建一个武器对象,这个武器就可以设置为全局唯一享元对象。

1、武器装备抽象类

public interface Weaponry {
    void releaseLethality();
}

2、武器装备无影剑类(这名起的真俗,凑合看吧)

public class ShadowlessSword implements Weaponry {
    private String name;
    private int lethality;
    
    public ShadowlessSword(String name, int lethality) {
        this.name = name;
        this.lethality = lethality;
    }

    @Override
    public void releaseLethality() {
        System.out.println("释放杀伤力: " + lethality);
    }
}

3、武器装备工厂,新建一个武器,共所有玩家共享。

public class WeaponryFactory {
    private static final Map<String, Weaponry> weaponries = new HashMap<>();
    static {
        weaponries.put("无影剑", new ShadowlessSword("无影剑", 100));
    }
    
    public static Weaponry getWeaponry(String name){
        return weaponries.get(name);
    }
}

4、玩家类

public class Gamers {
    private Weaponry weaponry;

    public Gamers(Weaponry weaponry) {
       this.weaponry = weaponry;
    }
    
    public void startUseWeaponry() {
        weaponry.releaseLethality();
    }

    public Weaponry getWeaponry(){
        return weaponry;
    }
}

5、测试类

public class Client {
    public static void main(String[] args) {
        Gamers gamers1 = new Gamers(WeaponryFactory.getWeaponry("无影剑"));
        gamers1.startUseWeaponry();

        Gamers gamers2 = new Gamers(WeaponryFactory.getWeaponry("无影剑"));
        gamers2.startUseWeaponry();
        System.out.println("武器是否一样:" + (gamers1.getWeaponry() == gamers2.getWeaponry()));
    }
}

6、运行结果
享元模式运行结果.png

三、享元模式在 Java 中的应用

1、在Integer中的使用,看下面代码,多么熟悉的面试题。答案输出是true和false。

Integer i1 = 56;
Integer i2 = 56;
Integer i3 = 129;
Integer i4 = 129;

System.out.println(i1 == i2);
System.out.println(i3 == i4);

分析:Integer 是一个对象,赋值的时候会自动装箱,变成对象。按理说i1i2是不同对象,应该不等才对,之所以结果相等是因为:Integer 用到了享元模式来复用对象。

  • 执行代码Integer i1 = 56; 底层会调用valueOf方法。
Integer i = Integer.valueOf(59);
  • valueOf方法代码如下,当输入的值在一定范围的时候,会直接从IntegerCache中获取。
public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high) 
        return IntegerCache.cache[i + (-IntegerCache.low)]; 
     return new Integer(i);
}
  • 这里的 IntegerCache 相当于生成享元对象的工厂类,提前创建了-128 - 127之前的整数对象,所以上面的结果一个是true,一个是false。56的对象是直接从IntegerCache 中获取到的并非新建对象。除了 Integer 类型之外,其他包装器类型,比如 LongShortByte 等,也都利用了享元模式来缓存 -128 到 127 之间的数据。
/**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */
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 =
            sun.misc.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() {}
}
  • 这个最大阈值是可以改的,修改方法在IntegerCache代码上面的注释了有,也不用记。
 -XX:AutoBoxCacheMax=<size>
  • 如下三种声明方式,后两种都会从缓存种拿,第一种会新建一个对象,所以推荐使用后两种进行声明。
Integer a = new Integer(33);
Integer a = 33;
Integer a = Integer.valueOf(33);

2、在String中的使用。看下面代码,和上面一样,答案输出是truefalse

String s1 = "哈哈";
String s2 = "哈哈";
String s3 = new String("哈哈");

System.out.println(s1 == s2);
System.out.println(s1 == s3);

Integer 类中要共享的对象,是在类加载的时候,就集中一次性创建好的。但是,对于字符串来说,我们没法事先知道要共享哪些字符串常量,所以没办法事先创建好,只能在某个字符串常量第一次被用到的时候,存储到常量池中,当之后再用到的时候,直接引用常量池中已经存在的即可,就不需要再重新创建了。

参考文章:
极客时间《设计模式》(王争)

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

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

相关文章

鉴源实验室丨软件代码结构化覆盖测试-语句覆盖

作者 | 李伟 上海控安安全测评部总监 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 引言&#xff1a; 之前我们一直在讲功能、性能、以及专项等相关的测试&#xff0c;这些测试主要集中在集成测试&#xff0c;系统验证等阶段&#x…

【快速傅里叶变换(fft)和逆快速傅里叶变换】生成雷达接收到的经过多普勒频移的脉冲雷达信号(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

颜值爆表!这款开源的API工具用起来更优雅!

作为一名后端开发者&#xff0c;我们经常会使用API工具来调试接口&#xff0c;之前一直使用的Postman&#xff0c;用多了感觉它有点不够轻量级&#xff0c;有时候打开也比较慢。最近发现了一款轻量级的开源API工具Insomnia&#xff0c;界面挺炫酷&#xff0c;功能也很实用&…

井下空气质量检测预警系统,煤矿生产、事故应急检测和实时监测

井下空气质量检测预警系统,煤矿生产、事故应急检测和实时监测 在煤矿生产中&#xff0c;空气质量是关系到矿工生命安全的重要因素。煤矿内部存在着各种有害气体&#xff0c;如甲烷、一氧化碳等&#xff0c;高浓度的有害气体会导致矿工中毒、窒息等危险情况&#xff0c;因此煤矿…

Linux journalctl命令详解(journalctl指令)(systemd服务默认日志管理工具)

文章目录 Linux Journalctl命令详解1. Journalctl简介2. Journalctl基础使用3. 过滤日志条目4. 时间戳和日志轮转5. 高级应用6. journalctl --help指令文档英文中文 注意事项journal日志不会将程序输出的空行显示&#xff0c;日志会被压缩得满满当当。journal日志不会自动持久化…

HTML5+CSS3+JS小实例:环形文字动画特效

实例:环形文字动画特效 技术栈:HTML+CSS+JS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content=&quo…

排序算法之详解冒泡排序

引入 冒泡排序顾名思义&#xff0c;就是像冒泡一样&#xff0c;泡泡在水里慢慢升上来&#xff0c;由小变大。虽然冒泡排序和冒泡并不完全一样&#xff0c;但却可以帮助我们理解冒泡排序。 思路 一组无序的数组&#xff0c;要求我们从小到大排列 我们可以先将最大的元素放在数组…

关于图像分类、图像识别和目标检测异同

计算机视觉是人工智能领域的一个重要分支&#xff0c;它旨在构建能够理解和处理图像、视频等视觉信息的计算机系统。在计算机视觉领域中&#xff0c;图像分类、图像识别和目标检测是三个重要的任务&#xff0c;当然目标跟踪、图像生成也是新的方向和延伸。 其实下面这幅图已经非…

A. Two Semiknights Meet

题目描述 可知走法为中国象棋中的象的走法 解题思路 利用结构体来存储两个 K K K的位置 x , y x,y x,y&#xff0c;因为两个 K K K同时走&#xff0c;所以会出现两种情况 相向而行&#xff0c;两者距离减少 相反而行&#xff0c;两者距离不变 我们完全可以不考虑格子是好…

记一次从Redis弱口令到RCE

Fscan扫描网段发现了一些开启了6379的服务器&#xff0c;逐个尝试了下未授权&#xff0c;然后尝试了下爆破 hydra爆破redis hydra -P [字典目录] redis://xxx.xxx.xxx.xxx结果还真让爆出来一个 得到密码后&#xff0c;连接上去&#xff0c;这里用的是Another Redis Desktop M…

polar si9000使用---1

1、软件界面 2、表面单端信号 表层单端走线&#xff1a;1、走线表面未覆盖绿油&#xff1b;2、参考表面为完整的地平面&#xff1b;3、走线同层不进行铺铜操作&#xff0c;或者同层铺铜的距离大于参考地到走线距离H1&#xff1b; 表层单端走线&#xff1a;1、走线表面覆盖绿油…

【自适应稀疏度量方法和RQAM】疏度测量、RQAM特征、AWSPT和基于AWSPT的稀疏度测量研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

wps 画项目进度甘特图

效果如上 步骤一&#xff1a; 创建excel 表格 步骤二&#xff1a; 选中开始时间和结束时间两列数据&#xff0c;右键设置单元格格式 步骤三&#xff1a; 选择数值&#xff0c;点击确定&#xff0c;将日期转成数值。 步骤四&#xff1a;插入图表 选中任务&#xff0c;开始时间…

什么是程序化交易接口?执行三步曲是什么?

在股市中的发展过程中&#xff0c;通过不断的更新迭代&#xff0c;从手动交易到自动交易的过程就有了历史的蜕变&#xff0c;那么对于程序化交易接口&#xff08;Application Programming Interface, API&#xff09;其实就是指为程序化交易提供的一组定义和规范&#xff0c;允…

【BASH】回顾与知识点梳理(三十九)

【BASH】回顾与知识点梳理 三十九 三十九. make、tarball、函数库及软件校验39.1 用 make 进行宏编译为什么要用 makemakefile 的基本语法与变量 39.2 Tarball 的管理与建议使用原始码管理软件所需要的基础软件Tarball 安装的基本步骤一般 Tarball 软件安装的建议事项 (如何移除…

概率和统计,最大似然估计(MLE),大后验概率估计(MAP)

目录 1、概率和统计是一个东西吗&#xff1f; 2、贝叶斯公式到底在说什么&#xff1f; 3、似然函数 4、最大似然估计&#xff08;MLE&#xff09; 5、最大后验概率估计&#xff08;MAP&#xff09; MLE VS MAP 总结 贝叶斯公式分成两派&#xff1a;唯物主义的频率学派&a…

变频器和plc之间无线MODBUS通讯

在工业现场由PLC远程控制变频器的应用非常常见&#xff0c;如果挖沟布线不便或者变频器在移动设备上&#xff0c;那么采用无线通讯就是最佳方案。 这里我们选用最常用的三菱 FX2N PLC和三菱变频器为例&#xff0c;并结合日系plc专用无线通讯终端DTD435M来说明PLC与变频器之间的…

LeetCode 0849. 到最近的人的最大距离

【LetMeFly】849.到最近的人的最大距离 力扣题目链接&#xff1a;https://leetcode.cn/problems/maximize-distance-to-closest-person/ 给你一个数组 seats 表示一排座位&#xff0c;其中 seats[i] 1 代表有人坐在第 i 个座位上&#xff0c;seats[i] 0 代表座位 i 上是空的…

Consistency Models终结扩散模型

最近看到一篇论文&#xff0c;觉得特别有意思&#xff0c;并且在学术界引起了不小的动静&#xff0c;他就是一致性模型&#xff0c;据说图像生成效果快、质量高&#xff0c;并且还可以实现零样本图像编辑&#xff0c;即不进行一些视觉任务训练&#xff0c;可以实现图像超分、修…

MySQL的select ... where ...会加锁吗?

先说答案&#xff1a;不会。但select … where … lock in share mode会加锁。实验如下。 存储引擎innodb&#xff0c;MySQL版本5.7。 1&#xff1a;select … where … 如下图&#xff1a; 1&#xff1a;select … where … lock in share mode 如下图&#xff1a; 接着我…