享元模式及其运用场景:结合工厂模式和单例模式优化内存使用

news2024/11/24 8:29:54

介绍

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享对象来减少内存使用,尤其是对于大量相似对象的场景。享元模式通常与工厂模式单例模式结合使用,从而有效地控制和复用对象的创建。在享元模式中,享元对象的核心思想是将不可变的部分(共享的状态)和可变的部分(外部状态)进行区分,从而优化系统性能。

工厂模式与单例模式

享元模式与工厂模式紧密结合,享元工厂负责管理共享的享元对象。工厂模式使得创建和管理享元对象变得统一和高效。除此之外,单例模式也常用于确保享元工厂在整个系统中唯一,避免重复创建享元工厂实例,从而节省资源。

下面代码采用静态内部类的方式实现单例模式,这种方式不仅能保证线程安全,还能确保只有在首次使用时才创建实例,具有懒加载特性。但是枚举才是最优的单例模式实现。感兴趣的同学可以参考这篇文章单例模式最优解----枚举

享元模式的结构

享元模式的核心结构包含以下几个角色:

  1. 抽象享元角色(Flyweight):这是一个接口或抽象类,声明了享元对象的公共方法。享元对象可以通过这些方法向外界提供共享的数据,同时也可以设置外部数据。

  2. 具体享元角色(Concrete Flyweight):实现了抽象享元接口,提供了共享的内部状态。在享元工厂中,这些具体享元对象可以通过共享池来复用。

  3. 非共享的具体享元角色(Unshared Flyweight):这些对象不适合共享,通常包含外部状态。每次使用时都会直接实例化。

  4. 享元工厂角色(Flyweight Factory):负责管理和提供享元对象。享元工厂会检查是否已经有符合要求的享元对象,如果没有则创建新的对象并返回。

享元模式中的共享与非共享状态

享元模式中有两种主要状态:

  • 内部状态:这些状态是享元对象的一部分,并且是共享的。内部状态不会随着环境的改变而改变。

  • 外部状态:这些状态是依赖于外部环境的,通常随时间、位置等变化。外部状态不会存储在享元对象中,而是通过方法传递给享元对象。

享元模式的关键在于将这两种状态进行分离,只有内部状态才能被共享,外部状态则由客户端负责传递。

示例:图形编辑器中的享元模式

在这里插入图片描述

在这个例子中,我们设计了一个简单的图形编辑器,其中有两种共享形状:圆形和正方形。每个图形的颜色作为内部状态共享,而位置作为外部状态传递。通过享元模式,我们可以复用相同颜色的图形对象,并为每个图形传递不同的位置。如果没有采用共享的方式,每次调用图形时都会创建新的对象,这样会导致大量内存浪费。但位置不能复用,这是根据外部环境改变的。

代码实现

// 抽象享元角色
interface Shape {
    void draw(String externalState);
}

// 具体享元类 - 圆形,内部状态是共享的
class Circle implements Shape {
    private String color;  // 内部状态,颜色是共享的

    public Circle(String color) {
        this.color = color;
    }

    @Override
    public void draw(String externalState) {
        System.out.println("Drawing Circle with color: " + color + " at position: " + externalState);
    }
}

// 具体享元类 - 正方形,内部状态是共享的
class Square implements Shape {
    private String color;  // 内部状态,颜色是共享的

    public Square(String color) {
        this.color = color;
    }

    @Override
    public void draw(String externalState) {
        System.out.println("Drawing Square with color: " + color + " at position: " + externalState);
    }
}

// 非共享的具体享元 - 线条,完全依赖外部状态
class Line implements Shape {
    @Override
    public void draw(String externalState) {
        System.out.println("Drawing Line at position: " + externalState);
    }
}

// 享元工厂
class ShapeFactory {
    private Map<String, Shape> shapeMap = new HashMap<>();

    private ShapeFactory() {}  // 私有构造函数,防止外部创建实例

    // 静态内部类实现单例模式
    private static class SingletonHelper {
        private static final ShapeFactory INSTANCE = new ShapeFactory();
    }

    // 获取单例实例
    public static ShapeFactory getInstance() {
        return SingletonHelper.INSTANCE;
    }

    // 获取共享的享元对象
    public Shape getShape(String type, String color) {
        String key = type + color;
        if (!shapeMap.containsKey(key)) {
            if (type.equals("Circle")) {
                shapeMap.put(key, new Circle(color));
            } else if (type.equals("Square")) {
                shapeMap.put(key, new Square(color));
            }
        }
        return shapeMap.get(key);
    }
}


public class FlyweightPatternExample {
    public static void main(String[] args) {
        // 享元工厂
        ShapeFactory shapeFactory = ShapeFactory.getInstance();

        // 创建和使用共享的享元对象
        Shape circle1 = shapeFactory.getShape("Circle", "Red");
        Shape circle2 = shapeFactory.getShape("Circle", "Red");
        Shape square1 = shapeFactory.getShape("Square", "Blue");

        // 绘制图形时,外部状态(位置)会变化
        circle1.draw("10, 20");  // 外部状态为位置
        circle2.draw("15, 25");
        square1.draw("30, 40");

        // 非共享的享元对象(直接实例化)
        Shape line = new Line();
        line.draw("50, 60");  // 外部状态为位置
    }
}

代码说明

  1. 共享的具体享元类

    • CircleSquare 是共享的享元对象,它们的颜色是内部状态。享元工厂会根据颜色来共享这些对象。
  2. 非共享的具体享元类

    • Line 类是非共享的享元类,它不存储任何内部状态,而是每次都需要通过外部状态(位置)来绘制。它没有参与享元工厂的共享池。
  3. 享元工厂

    • ShapeFactory 类负责管理和返回共享的享元对象。它使用一个 Map 来缓存已创建的享元对象,避免重复创建相同的对象。
  4. 客户端使用

    • 客户端首先通过享元工厂请求共享的图形对象(如红色圆形)。如果该对象已存在,则直接返回;否则,创建一个新的对象。
    • 对于非共享的对象(如线条),客户端直接实例化,而不通过享元工厂。

总结

享元模式通过共享对象的方式有效减少了内存使用,尤其适用于对象数量庞大且状态相似的场景。JDK中也有享元模式的应用,感兴趣的同学可以往这看---->JDK享元模式的运用

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

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

相关文章

【RabbitMQ】03-交换机

1. 交换机 2. Fanout交换机 广播。生产者向exchange发消息 SpringBootTest public class SpringAmqpTest {Autowiredpublic RabbitTemplate rabbitTemplate;Testvoid testSimple() {String exchangName "hmall.fabout";rabbitTemplate.convertAndSend(exchangName…

【赵渝强老师】安装部署Memcached

Memcached是一个高性能的分布式的内存对象缓存系统。通过使用Memcached可以支持高负载的网站系统&#xff0c;以分担数据库的压力。Memcached通过在内存里维护一个统一的巨大的Hash表来存储各种格式的数据&#xff0c;包括图像、视频、文件以及数据库检索的结果等。但是Memcach…

代码要走的路:编程“三部曲”

代码要成为可以运行的程序&#xff0c;总共有3步&#xff1a; 1&#xff0e;编辑&#xff08;edit&#xff09; 这里的编辑不是像出版编辑那样&#xff0c;只把现成的东西修修改改&#xff0c;而是指编写代码。 编写代码是实实在在的原创&#xff0c;不是整理加工&#xff0…

支持向量机相关证明 解的稀疏性

主要涉及拉格朗日乘子法&#xff0c;对偶问题求解

漫途焊机安全生产监管方案,提升安全生产管理水平!

随着智能制造时代的到来&#xff0c;企业安全生产管理的重要性日益凸显。特别是在现代工厂中&#xff0c;焊机的安全生产监管成为了一个不容忽视的重要环节。传统的焊机安全生产监管方式存在诸多不足&#xff0c;如人工巡检频率低、数据延迟、安全隐患发现不及时等问题。因此&a…

【dvwa靶场:XSS系列】XSS (Reflected)低-中-高级别,通关啦

一、低级low 简单拿捏 <script>alert(123)</script>二、中级middle 源码过滤了script但是没有过滤大小写&#xff0c;改成大写S <Script>alert(123)</script>三、高级high 比中级高&#xff0c;过滤了script并且以及大小写&#xff0c;使用其他标…

太速科技-634-基于3U PXIe的VU3P FMC+数据接口板

基于3U PXIe的VU3P FMC数据接口板 一、产品概述 板卡是一款基于 3U PXIE 总线架构的高性能数据预处理FMC 载板&#xff0c;具有 1 个 FMC&#xff08;HPC&#xff09;接口&#xff0c;1 个 X8 GTH 背板互联接口&#xff0c;可以实现 1 路 PCIe x8。板卡主控芯片采用Xilin…

【LLM Agents体验】Dify框架的安装指南

Dify简介&#xff1a; 核心功能‌12 ‌Dify是一款开源的大语言模型(LLM)应用开发平台&#xff0c;融合了后端即服务&#xff08;Backend as a Service, BaaS&#xff09;和LLMOps的理念&#xff0c;使开发者可以快速搭建生产级的生成式AI应用。LLMOps涵盖了大型语言模型的开发、…

推荐一款PowerPoint转Flash工具:iSpring Suite

iSpring Suite是一款PowerPoint转Flash工具&#xff0c;使用iSpring Suite 8可以轻松的将PPT演示文档转换为对Web友好的Flash影片格式。软件界面简洁&#xff0c;使用方便。为什么要转换成flash格式呢?Flash格式的最大特点是体积小巧、易于分发&#xff0c;兼容所有的操作系统…

数据库->视图

目录 一、视图 1.什么是视图 ​编辑 2.创建视图 1.语法 3.使用视图 4.视图的功能 1.屏蔽相关字段 2.对外提供统一访问规范 3.视图和真实表进行表连接查询 5.修改数据 6.注意事项 7.删除视图 1.语法 8.视图的优点 1. 简单性 2. 安全性 3. 逻辑数据独⽴性 4. 重…

影响神经网络速度的因素- FLOPs、MAC、并行度以及计算平台

影响神经网络速度的四个主要因素分别是 FLOPs&#xff08;浮点操作数&#xff09;、MAC&#xff08;内存访问成本&#xff09;、并行度以及计算平台。这些因素共同作用&#xff0c;直接影响到神经网络的计算速度和资源需求。 1. FLOPs&#xff08;Floating Point Operations&a…

Java Development Kit (JDK) 详解

什么是 JDK&#xff1f; JDK 是 Java Development Kit 的缩写&#xff0c;是一组用于开发 Java 应用程序的软件开发工具和库的集合。JDK 包含了 Java 运行时环境&#xff08;JRE&#xff09;和 Java 虚拟机&#xff08;JVM&#xff09;&#xff0c;以及一系列开发工具和库。 …

Rust 力扣 - 1652. 拆炸弹

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们只需要遍历长度长度为k的窗口&#xff0c;然后把窗口内数字之和填充到结果数组中的对应位置即可 题解代码 impl Solution {pub fn decrypt(code: Vec<i32>, k: i32) -> Vec<i32> {let n c…

AAA 数据库事务隔离级别及死锁

目录 一、事务的四大特性&#xff08;ACID&#xff09; 1. 原子性(atomicity)&#xff1a; 2. 一致性(consistency)&#xff1a; 3. 隔离性(isolation)&#xff1a; 4. 持久性(durability)&#xff1a; 二、死锁的产生及解决方法 三、事务的四种隔离级别 0 .封锁协议 …

华为HarmonyOS借助AR引擎帮助应用实现虚拟与现实交互的能力3-获取设备位姿

设备位姿描述了物体在真实世界中的位置和朝向。AR Engine提供了世界坐标下6自由度&#xff08;6DoF&#xff09;的位姿计算&#xff0c;包括物体的位置&#xff08;沿x、y、z轴方向位移&#xff09;和朝向&#xff08;绕x、y、z轴旋转&#xff09;。通过AR Engine&#xff0c;您…

Ubuntu 扩容磁盘

1.没有机子&#xff0c;用虚拟机模拟一下将sdc扩到sdb下面去 2.先查看磁盘是否为ext4的格式 lsblk -f 3.发现不是 那就格式化一下 mkfs.ext4 /dev/sdc 4.转换为物理卷 pvcreate /dev/sdc 5.查看所要扩容的vg名称 vgs 6.物理机扩容到卷组 vgextend vgHome /dev/sdc 7.查看目…

真·香!深度体验 zCloud 数据库云管平台 -- DBA日常管理篇

点击蓝字 关注我们 zCloud 作为一款业界领先的数据库云管平台&#xff0c;通过云化自治的部署能力、智能巡检和诊断能力、知识即代码的沉淀能力&#xff0c;为DBA的日常管理工作带来了革新式的简化与优化。经过一周的深度体验&#xff0c;今天笔者与您深入探讨 zCloud 在数据库…

大数据之多级缓存方案

多级缓存介绍&#xff1f;多级缓存优缺点&#xff0c;应用场景&#xff1f;多级缓存架构&#xff1f; 多级缓存介绍 多级缓存方案是一种优化手段&#xff0c;通过在多个级别上存储数据来提高应用程序的性能和响应速度。以下是对多级缓存方案的详细解析&#xff1a; 一、多级缓…

前端三件套(HTML + CSS + JS)

前言&#xff1a; 前端三件套&#xff0c;会用就行 毕竟在后面学习JavaWeb&#xff0c;以及在学习vue的时候也有帮助 前端三件套&#xff1a; HTML 定义网页的结构和内容。CSS 负责网页的样式和布局。JavaScript 添加动态交互和功能。 使用到的工具是Visual Studio Code 即…

Zabbix proxy 主动模式的实现

1. 准备三台机器 zabbix-server10.0.0.200zabbix-agent10.0.0.203zabbix-proxy10.0.0.204 2. 创建独立的数据库&#xff08;最好部署在单独的机器上&#xff0c;或者部署在porxy机器上&#xff09; # 按照官网下载 proxy 的步骤中创建库和用户即可 # mysql -uroot -p passwo…