【深入理解设计模式】享元设计模式

享元设计模式

在这里插入图片描述

概述

享元设计模式(Flyweight Design Pattern)是一种用于性能优化的设计模式,它通过共享尽可能多的相似对象来减少对象的创建,从而降低内存使用和提高性能。享元模式的核心思想是将对象的共享部分提取出来,使得多个对象可以共享同一个享元对象,从而减少对象的创建。

定义:

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

结构

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

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

享元模式的结构如下:

  1. 抽象享元类(Flyweight):定义一个抽象类,包含一个享元对象的属性以及一个构造函数。

  2. 具体享元类(ConcreteFlyweight):实现抽象享元类,定义具体的享元对象。

  3. 享元工厂类(FlyweightFactory):负责创建和管理享元对象。享元工厂类会缓存已经创建的享元对象,当需要获取享元对象时,首先从缓存中查找,如果找不到,则创建一个新的享元对象并将其添加到缓存中。

享元模式的实现示例:

以下是一个简单的享元模式实现示例:

// 抽象享元类
public abstract class Flyweight {
    public abstract void operation();
}

// 具体享元类
public class ConcreteFlyweight extends Flyweight {
    private String state;

    public ConcreteFlyweight(String state) {
        this.state = state;
    }

    @Override
    public void operation() {
        System.out.println("ConcreteFlyweight: " + state);
    }
}

// 享元工厂类
public class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String state) {
        if (!flyweights.containsKey(state)) {
            flyweights.put(state, new ConcreteFlyweight(state));
        }
        return flyweights.get(state);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight flyweight1 = factory.getFlyweight("state1");
        Flyweight flyweight2 = factory.getFlyweight("state2");
        Flyweight flyweight3 = factory.getFlyweight("state1");

        flyweight1.operation();
        flyweight2.operation();
        flyweight3.operation();
    }
}

在这个示例中,我们定义了一个抽象享元类Flyweight和一个具体享元类ConcreteFlyweightFlyweightFactory类负责创建和管理享元对象,它使用一个HashMap来缓存已经创建的享元对象。客户端通过FlyweightFactory类来获取享元对象,并使用它们进行操作。

示例二:

/**
 * @author OldGj 2024/02/29
 * @version v1.0
 * @apiNote 享元设计模式 - 抽象享元类
 */
public abstract class AbstractBox {

    public abstract String getSharp();

    public void display(String color) {
        System.out.println("形状:" + this.getSharp() + ",颜色:" + color);
    }
}

/**
 * @author OldGj 2024/02/29
 * @version v1.0
 * @apiNote 具体享元类 - I图形
 */
public class IBox extends AbstractBox {

    @Override
    public String getSharp() {
        return "I";
    }
}


/**
 * @author OldGj 2024/02/29
 * @version v1.0
 * @apiNote 具体享元类 - L图形
 */
public class LBox extends AbstractBox {

    @Override
    public String getSharp() {
        return "L";
    }
}


/**
 * @author OldGj 2024/02/29
 * @version v1.0
 * @apiNote 具体享元类 - O图形
 */
public class OBox extends AbstractBox {

    @Override
    public String getSharp() {
        return "O";
    }
}

/**
 * @author OldGj 2024/02/29
 * @version v1.0
 * @apiNote 图形工厂类 - 享元工厂类 【单例实现】
 */
public class BoxFactory {

    private final Map<String, AbstractBox> map;
    private static final BoxFactory factory = new BoxFactory();

    private BoxFactory() {
        map = new HashMap<>();
        map.put("I", new IBox());
        map.put("O", new OBox());
        map.put("L", new LBox());
    }

    public static BoxFactory getInstance() {
        return factory;
    }

    public AbstractBox createBox(String name) {
        return map.get(name);
    }
}
/**
 * @author OldGj 2024/02/29
 * @version v1.0
 * @apiNote 客户端 - 测试类
 */
public class Client {

    public static void main(String[] args) {
        BoxFactory factory = BoxFactory.getInstance();
        AbstractBox LBox = factory.createBox("L");
        LBox.display("红色"); // 外部状态

        AbstractBox oBox = factory.createBox("O");
        oBox.display("黑色"); // 外部状态

        AbstractBox IBox = factory.createBox("I");
        IBox.display("白色"); // 外部状态

        AbstractBox IBox2 = factory.createBox("I");
        IBox2.display("蓝色"); // 外部状态
        System.out.println("是否共享同一个对象:" + (IBox == IBox2));
    }
}

在这里插入图片描述

优缺点:

享元模式的优点:

  1. 减少对象创建:享元模式通过共享相似对象,减少了对象的创建,从而降低了内存使用和提高了性能。

  2. 提高性能:享元模式通过减少对象创建,提高了性能。

  3. 方便管理:享元模式将对象的共享部分提取出来,使得对象可以轻松地管理和维护。

享元模式的缺点:

  1. 享元对象共享:享元对象共享可能会导致一些问题,例如线程安全问题。享元模式要求享元对象是线程安全的,这可能会导致性能下降。

  2. 享元对象状态:享元对象的状态可能会影响其他使用相同享元对象的客户端。享元模式要求享元对象的状态是独立的,这可能会导致享元对象的状态难以维护。

  3. 享元对象生命周期:享元对象的生命周期可能会比客户端使用的时间长,这可能会导致内存泄漏。享元模式要求享元对象具有较长的生命周期,这可能会导致内存使用增加。

使用场景:

享元模式通常用于以下场景:

  1. 对象数量多且相似:当对象数量多且相似时,享元模式可以显著减少对象的创建,提高性能。

  2. 对象共享属性多:当对象共享属性多时,享元模式可以减少内存使用,提高性能。

  3. 对象创建开销大:当对象创建开销大时,享元模式可以减少对象创建的开销,提高性能。

JDK源码解析

Integer类使用了享元模式。我们先看下面的例子:

public class Demo {
    public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;

        System.out.println("i1和i2对象是否是同一个对象?" + (i1 == i2));

        Integer i3 = 128;
        Integer i4 = 128;

        System.out.println("i3和i4对象是否是同一个对象?" + (i3 == i4));
    }
}

运行上面代码,结果如下:

为什么第一个输出语句输出的是true,第二个输出语句输出的是false?通过反编译软件进行反编译,代码如下:

public class Demo {
    public static void main(String[] args) {
        Integer i1 = Integer.valueOf((int)127);
        Integer i2 Integer.valueOf((int)127);
        System.out.println((String)new StringBuilder().append((String)"i1\u548ci2\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f").append((boolean)(i1 == i2)).toString());
        Integer i3 = Integer.valueOf((int)128);
        Integer i4 = Integer.valueOf((int)128);
        System.out.println((String)new StringBuilder().append((String)"i3\u548ci4\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f").append((boolean)(i3 == i4)).toString());
    }
}

上面代码可以看到,直接给Integer类型的变量赋值基本数据类型数据的操作底层使用的是 valueOf() ,所以只需要看该方法即可

public final class Integer extends Number implements Comparable<Integer> {
    
	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 {
            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) {
                }
            }
            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 默认先创建并缓存 -128 ~ 127 之间数的 Integer 对象,当调用 valueOf 时如果参数在 -128 ~ 127 之间则计算下标并从缓存中返回,否则创建一个新的 Integer 对象。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

lqb省赛日志[2/37]

一只小蒟蒻备考蓝桥杯的日志 文章目录 笔记&#xff01;lqb不能用to_string和atoi历史遗留问题1 刷题心得小结 笔记 &#xff01;lqb不能用to_string和atoi 有替代方法 参考 不使用C 11的整数转字符串 C语言提供了一种方法。 #include sstream &#xff08;我没学&#xff0…

MySQL面试题-锁(答案版)

锁 1、MySQL 有哪些锁&#xff1f; &#xff08;1&#xff09;全局锁 加了全局锁之后&#xff0c;整个数据库就处于只读状态了&#xff0c;这时其他线程执行以下操作&#xff0c;都会被阻塞&#xff1a; 对数据的增删改操作&#xff0c;比如 insert、delete、update等语句&…

【粉丝福利】探秘内部审计数字化之道:精准解析转型方法与成功路径

&#x1f33c;前言 内部审计是一种独立的、客观的确认和咨询活动&#xff0c;包括鉴证、识别和分析问题以及提供管理建议和解决方案。狭义的数字化转型是指将企业经营管理和业务操作的各种行为、状态和结果用数字的形式来记录和存储&#xff0c;据此再对数据进行挖掘、分析和应…

【Linux】--- Linux编译器-gcc/g++、调试器-gdb、项目自动化构建工具-make/Makefile 使用

目录 一、Linux编译器-gcc/g1.1 gcc/g 使用方法1.2 程序的翻译过程1.3 链接 -- 动静态链接特点及区别 二、Linux调试器-gdb2.1 背景2.2 使用方法 三、Linux项目自动化构建工具-make/Makefile3.1 背景3.2 原理3.3 项目清理 一、Linux编译器-gcc/g 1.1 gcc/g 使用方法 格式&…

Linux mmap系统调用

文章目录 前言一、mmap()函数简介二、代码演示2.1 mmap使用场景2.2 私有匿名映射2.3 私有文件映射2.4 共享匿名映射2.5 共享文件映射 参考 前言 NAMEmmap, munmap - map or unmap files or devices into memorySYNOPSIS#include <sys/mman.h>void *mmap(void *addr, siz…

如何使用 ArcGIS Pro 制作三维地形图

伴随硬件性能的提高和软件算法的优化&#xff0c;三维地图的应用场景会越来越多&#xff0c;这里为大家介绍一下在ArcGIS Pro怎么制作三维地形图&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的DEM和影像数据&#xff0c;除了DEM和影像数据…

Python数据处理实战(4)-上万行log数据提取并作图进阶版

系列文章&#xff1a; 0、基本常用功能及其操作 1&#xff0c;20G文件&#xff0c;分类&#xff0c;放入不同文件&#xff0c;每个单独处理 2&#xff0c;数据的归类并处理 3&#xff0c;txt文件指定的数据处理并可视化作图 4&#xff0c;上万行log数据提取并作图进阶版&a…

vue3的开发小技巧

「总之岁月漫长&#xff0c;然而值得等待。」 目录 父组件调用子组件函数如何访问全局api 父组件调用子组件函数 ref, defineExpose //父组件 代码 <child ref"ch">this.$refs.ch.fn();//子组件 函数抛出 const fn () > { }; defineExpose({ fn });如何…

Type-C接口PD协议统一:引领电子科技新纪元的优势解析

在电子科技日新月异的今天&#xff0c;充电接口的统一化已经成为了业界的一大趋势。其中&#xff0c;Type-C接口凭借其传输速度快、使用便捷等优点&#xff0c;迅速成为了市场上的主流选择。而PD&#xff08;Power Delivery&#xff09;协议的统一&#xff0c;更是为Type-C接口…

投标中项目组织结构的设置以及调整(样式表,多级列表)

投标中项目组织结构的设置以及调整&#xff08;样式表&#xff0c;多级列表&#xff09;&#xff1a; 投标项目中需要处理大规模的文字排版&#xff0c;就是需要用到样式表&#xff08;解决层级关系&#xff09;&#xff0c;多级列表&#xff08;解决自动编号的问题&#xff0…

CSP-J 2021 T2 插入排序

文章目录 题目传送门算法解析总代码提交记录尾声 题目传送门 洛谷 P7910 [CSP-J 2021] 插入排序 算法解析 千万不要题目让你插入排序你就插入排序 首先可以用 p a i r pair pair 来存储元素的值&#xff08; f i r s t first first&#xff09;和原来的下标&#xff08; s…

Vue组件中的scoped属性

Vue组件中的scoped属性的作用是&#xff1a;当前的单文件组件的css样式只用于当前组件的template模板&#xff0c;在Vue脚手架汇总组件间关系时避免样式命名重复的情况。 原理&#xff1a;使用data-*属性在template模板中使用样式的HTML元素上添加额外属性&#xff0c;再利用标…

【UE5】游戏框架GamePlay

游戏框架 游戏 由 游戏模式(GameMode) 和 游戏状态(GameState) 所组成 加入游戏的 人类玩家 与 玩家控制器(PlayerController) 相关联 玩家控制器允许玩家在游戏中拥有 HUD&#xff0c;这样他们就能在关卡中拥有物理代表 玩家控制器还向玩家提供 输入控制&#xff08;Input…

【Qt】四种绘图设备详细使用

绘图设备有4个: **绘图设备是指继承QPainterDevice的子类————**QPixmap QImage QPicture QBitmap(黑白图片) QBitmap——父类QPixmapQPixmap图片类&#xff0c;主要用来显示&#xff0c;它针对于显示器显示做了特殊优化&#xff0c;依赖于平台的&#xff0c;只能在主线程…

掘根教你拿捏C++异常(try,catch,throw,栈解退,异常规范,异常的重新抛出)

在介绍异常之前&#xff0c;我觉得很有必要带大家了解一下运行时错误和c异常出现之前的处理运行时错误的方式。这样子能更深入的了解异常的作用和工作原理 运行阶段错误 我们知道&#xff0c;程序有时候会遇到运行阶段错误&#xff0c;导致程序无法正常运行下去 C在运行时可…

【Springer出版 · EI检索】| 第二届先进无人飞行系统国际会议(ICAUAS 2024)

会议简介 Brief Introduction 2024年第二届先进无人飞行系统国际会议(ICAUAS 2024) 会议时间&#xff1a;2024年6月14日-16日 召开地点&#xff1a;中国南昌 大会官网&#xff1a;ICAUAS 2024-2024 2nd International Conference on Advanced Unmanned Aerial Systems2024 2nd …

即插即用篇 | YOLOv8 引入 ParNetAttention 注意力机制 | 《NON-DEEP NETWORKS》

论文名称:《NON-DEEP NETWORKS》 论文地址:https://arxiv.org/pdf/2110.07641.pdf 代码地址:https://github.com/imankgoyal/NonDeepNetworks 文章目录 1 原理2 源代码3 添加方式4 模型 yaml 文件template-backbone.yamltemplate-small.yamltemplate-large.yaml

视频监控平台EasyCVR+4G/5G应急布控球远程视频监控方案

随着科技的不断发展&#xff0c;应急布控球远程视频监控方案在公共安全、交通管理、城市管理等领域的应用越来越广泛。这种方案通过在现场部署应急布控球&#xff0c;实现对特定区域的实时监控&#xff0c;有助于及时发现问题、快速响应&#xff0c;提高管理效率。 智慧安防视…

vite+vue3门户网站菜单栏动态路由控制

门户网站用户端需要分板块展示&#xff0c;板块内容由管理端配置&#xff0c;包括板块名称&#xff0c;访问路径&#xff0c;路由组件&#xff0c;展示顺序&#xff0c;是否展示。如下图所示&#xff1a; 用户访问门户网站时&#xff0c;展示菜单跳转通过板块配置&#xff0c;动…

Python笔记(四)—— Python函数

4.1 函数的初体验 函数 函数&#xff1a;是组织好的&#xff0c;可重复使用的&#xff0c;用来实现特定功能的代码段 name "itheima" length len(name) print(length) 运行结果&#xff1a; 思考&#xff1a;为什么随时都可以使用len()统计长度 因为&#xff…