当前位置: 首页 > news >正文

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

介绍

享元模式(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;}@Overridepublic 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;}@Overridepublic void draw(String externalState) {System.out.println("Drawing Square with color: " + color + " at position: " + externalState);}
}// 非共享的具体享元 - 线条,完全依赖外部状态
class Line implements Shape {@Overridepublic 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享元模式的运用

相关文章:

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

介绍 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享对象来减少内存使用&#xff0c;尤其是对于大量相似对象的场景。享元模式通常与工厂模式和单例模式结合使用&#xff0c;从而有效地控制和复用对象的创建。在享元模式中&am…...

【物联网技术】ESP8266 WIFI模块在STA模式下实现UDP与电脑/手机网络助手通信——UDP数据透传

前言:完成ESP8266 WIFI模块在STA模式下实现UDP与电脑/手机网络助手通信——实现UDP数据透传 STA模式,通俗来说就是模块/单片机去连接路由器/热点来通信。 UDP协议,是传输层协议,UDP没有服务器和客户端的说法。 本实验需要注意,wifi模块/单片机与电脑/手机需要连接在同一个…...

【SQL Server】华中农业大学空间数据库实验报告 实验一 数据库

实验目的 熟悉了解掌握SQL Server软件的基本操作与使用方法&#xff0c;认识界面&#xff0c;了解其两个基本操作系统文件&#xff0c;并能熟练区分与应用交互式与T-SQL式两种方法在SQL Server中如何进行操作&#xff1b;学习有关数据库的基本操作&#xff0c;包括&#xff1a…...

操作系统页面置换算法Java实现(LFU,OPT,LRU,LFU,CLOCK)

FIFO先进先出算法 java import java.util.LinkedList; import java.util.Queue; public class Main { //先进先出的思想 是 用一个队列去模拟数据 如果当前不存在就是发生缺页中断了 就需要添加 如果已经满了 将队头的元素出队 即可 //先进先出 就是一个数组 frameCount publi…...

Request和Response

前言 这一节主要讲的是Request和Response还有一些实例 1. 介绍 就是这两个参数 WebServlet("/demo7") public class ServletDemo7 extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletExcepti…...

【青牛科技】GC8549替代LV8549/ONSEMI在摇头机、舞台灯、打印机和白色家电等产品上的应用分析

引言 在现代电子产品中&#xff0c;控制芯片的性能直接影响到设备的功能和用户体验。摇头机、舞台灯、打印机和白色家电等领域对控制精度、功耗和成本等方面的要求日益提高。LV8549/ONSEMI等国际品牌的芯片曾是这些产品的主要选择&#xff0c;但随着国内半导体技术的进步&…...

(十二)JavaWeb后端开发——MySQL数据库

目录 1.数据库概述 2.MyQSL 3.数据库设计 DDL 4.MySQL常见数据类型 5.DML 1.数据库概述 数据库&#xff1a;DataBase(DB)&#xff0c;是存储和管理数据的仓库 数据库管理系统&#xff1a;DataBase ManagementSystem(DBMS)&#xff0c;操纵和管理数据库的大型软件 SQL&a…...

pnpm管理多工作区依赖

pnpm是一个支持多包仓库的一个包管理工具,那么怎么可以在项目根目录下执行pnpm install的时候,也能同步让所有的工作区都能够通安装依赖呢? 方式一,在执行pnpm install指令的时候,添加recursive参数: pnpm install --recursive 方式二,在项目的根目录下通过pnpm的配置文件p…...

如何在本地Linux服务器搭建WordPress网站结合内网穿透随时随地可访问

文章目录 前言1. 安装WordPress2. 创建WordPress数据库3. 安装相对URL插件4. 安装内网穿透发布网站4.1 命令行方式&#xff1a;4.2. 配置wordpress公网地址 5. 配置WordPress固定公网地址 前言 本文主要介绍如何在Linux Ubuntu系统上使用WordPress搭建一个本地网站&#xff0c…...

二、应用层,《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》

文章目录 零、前言一、应用层协议原理1.1 网络应用的体系结构1.1.1 客户-服务器(C/S)体系结构1.1.2 对等体&#xff08;P2P&#xff09;体系结构1.1.3 C/S 和 P2P体系结构的混合体 1.2 进程通信1.2.1 问题1&#xff1a;对进程进行编址&#xff08;addressing&#xff09;&#…...

面粉直供系统|基于java和小程序的食品面粉直供系统设计与实现(源码+数据库+文档)

面粉直供系统 目录 基于java和小程序的食品面粉直供系统设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#x…...

十四:java web(6)-- Spring Spring MVC

目录 Spring MVC 1.1 Spring MVC 概述 1.1.1 什么是 MVC 模式 1.1.2 Spring MVC 工作原理 1.2 Spring MVC 核心组件 1.2.1 DispatcherServlet 1.2.2 控制器&#xff08;Controller&#xff09; 1.2.3 请求映射&#xff08;RequestMapping&#xff09; 1.2.4 视图解析器…...

Java代码实现策略模式处理支付付款业务

1.需求:因为付款功能集成的第三方支付SDK越来越来多不好维护,改用策略模式实现,来代替代码中多余的if else 判断。 2.什么是策略模式? 策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为。该模式将不同的算法封装成独立的策略类,并使这些…...

unity3d————四元数概念

一、定义与表示 四元数是由一个实数部分和三个虚数部分组成&#xff0c;通常表示为q w xi yj zk&#xff0c;其中w是实数&#xff0c;x、y、z是实数系数&#xff0c;i、j、k是虚数单位&#xff0c;满足以下关系&#xff1a; i j k -1ij k&#xff0c;ji -kjk i&…...

spring相关的面试题

Spring 框架是 Java 开发中最常用的框架之一&#xff0c;因此在面试中经常会被问到与 Spring 相关的问题。以下是一些常见的 Spring 面试题及其答案。 基础概念 什么是 Spring 框架&#xff1f; Spring 框架是一个开源的 Java 平台&#xff0c;用于构建企业级应用程序。它提供…...

STM32外设之SPI的介绍

### STM32外设之SPI的介绍 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;主要用于EEPROM、FLASH、实时时钟、AD转换器等外设的通信。SPI通信只需要四根线&#xff0c;节约了芯片的管脚&#x…...

二十三、Mysql8.0高可用集群架构实战

文章目录 一、MySQL InnoDB Cluster1、基本概述2、集群架构3、搭建一主两从InnoDB集群3.1、 安装3个数据库实例3.2、安装mysqlrouter和安装mysqlshell3.2.1、安装mysql-router3.2.2、安装mysql-shell 3.3、InnoDB Cluster 初始化3.3.1、参数及权限配置预需求检测3.3.2、初始化I…...

docker file 精简规则

在编写 Dockerfile 时&#xff0c;精简规则不仅有助于减小镜像大小&#xff0c;还能提高构建速度和可维护性。以下是一些常见的精简 Dockerfile 规则&#xff1a; 1. 尽量合并 RUN 指令 每个 RUN 指令会产生一个新的镜像层&#xff0c;因此多个命令可以合并为一个 RUN 指令&a…...

前端加密方式详解与选择指南

在当今数字化时代&#xff0c;前端数据安全的重要性日益凸显。本文将深入探讨前端加密的多种方式&#xff0c;为你提供选择适合项目加密方式的实用策略&#xff0c;并分享一些实际案例及相应代码。 一、前端加密方式汇总 &#xff08;一&#xff09;HTTPS 加密 HTTPS 是在 H…...

【React】条件渲染——逻辑与运算符

条件渲染——逻辑与&&运算符 你会遇到的另一个常见的快捷表达式是 JavaScript 逻辑与&#xff08;&&&#xff09;运算符。在 React 组件里&#xff0c;通常用在当条件成立时&#xff0c;你想渲染一些 JSX&#xff0c;或者不做任何渲染。 function Item({ nam…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...

结构化文件管理实战:实现目录自动创建与归类

手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题&#xff0c;进而引发后续程序异常。使用工具进行标准化操作&#xff0c;能有效降低出错概率。 需要快速整理大量文件的技术用户而言&#xff0c;这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB&#xff0c;…...