设计模式详解(十三)——享元模式

享元模式简介

享元模式定义
享元模式(Flyweight Pattern)是一种用于优化性能的软件设计模式。它是一种结构型的设计模式。它的主要目的是通过共享物件来减少内存使用量,同时分享信息给尽可能多的相似物件,从而降低内存消耗和提高系统性能。这种模式特别适用于那些因为重复而导致使用大量内存的大量物件。享元模式将对象的状态分为内部状态和外部状态,其中一些具有相同内部状态的对象可以被多个对象共享,而不是为每个对象都创建新的实例;而外部状态是变化的,不能共享。通过共享不变的部分,可以减少不必要的对象创建和内存消耗,提高系统性能。

享元模式包含以下角色:

  1. 抽象享元角色(Flyweight Interface):享元对象抽象了一个接口或抽象类,用于声明享元对象的方法。这些方法使得外部状态能够以参数形式传入。通常这个接口不会涉及到外部状态的具体细节,它仅仅关注于内部状态的操作。
  2. 具体享元角色(Concrete Flyweight):具体享元角色实现了抽象享元接口,并包含内部状态的存储。内部状态是享元对象可以共享的部分,具体享元角色可以被多个客户端对象共享。
  3. 享元工厂角色(Flyweight Factory):负责创建和管理享元对象。它维护了一个享元对象的缓存池,当客户端请求享元对象时,工厂会首先检查缓存池中是否存在具有相同内部状态的享元对象,如果存在则直接返回,否则创建一个新的享元对象并添加到缓存池中。
  4. 客户端角色(Client):持有对享元对象的引用,并负责在必要时通过享元工厂获取享元对象。客户端角色与享元对象交互,并可能提供外部状态给享元对象。

享元模式优缺点:
优点:

  1. 减少内存消耗:通过共享大量相似对象,可以减少系统中对象的数量,从而降低内存消耗。这在处理大量相似对象时尤为有效,可以显著提高系统的资源利用率。
  2. 性能提升:由于共享的对象可以被多个客户端共享,所以减少了对象的创建和销毁次数,享元模式可以提高系统的性能。特别是在频繁创建和销毁对象的场景中,享元模式能够显著减少这些操作带来的开销。
  3. 降低系统复杂性:享元模式将内部状态与外部状态是分离的状态,使得系统更容易理解和维护。内部状态由享元对象管理,外部状态由客户端管理,降低了系统的复杂性,可以有效地降低对象间的耦合度。

缺点:

  1. 增加编程复杂性:实现享元模式需要将对象的状态分为内部状态和外部状态,需要对内部状态和外部状态进行较为繁琐的区分这要求开发者对系统的状态管理有深入的理解。
  2. 增加系统的维护性:由于享元模式将对象的状态分为内部状态和外部状态,这可能会增加系统的复杂度,使得系统的维护变得困难。特别是在处理复杂的业务逻辑时,需要格外小心以确保状态的正确性和一致性。
  3. 降低代码的可读性:由于享元模式涉及到对对象状态的划分和共享,可能会使得代码的逻辑变得复杂,降低代码的可读性。这要求开发者在编写代码时注重注释和文档,以提高代码的可理解性。
  4. 可能引入线程安全问题:如果多个线程同时访问和修改共享对象,可能会导致线程安全问题。因此,在使用享元模式时,需要特别注意线程安全的处理。

使用场景

  1. 当程序中需要创建大量相似对象,并且这些对象可以共享一部分状态时,使用享元模式可以节省内存和提高性能。
  2. 当创建对象的成本较高,且对象的状态可以分为内部状态和外部状态时,可以考虑使用享元模式。内部状态可以由对象共享,而外部状态则通过参数传递给享元对象。这样可以减少创建对象的数量,提高系统的可扩展性和性能。
  3. 在需要处理大量数据的系统中,可能存在大量的重复对象。这些对象可以通过享元模式来共享,减少对象的创建和内存消耗,提高系统的性能和可扩展性。
  4. 在高并发的系统中,可能存在大量的请求和对象。通过享元模式共享对象,可以减少对象的创建和销毁,提高系统的并发处理能力和响应速度。

以下举一个享元模式的例子:
下面通过一个简单的例子来演示。将一辆小汽车可以看做是一个享元对象,共享的部分是小汽车的基本属性,比如颜色,发动机排量等。相同颜色、发动机排量的小汽车可以共享同一个对象,不需要每次创建新的对象。

创建抽象享元角色(Flyweight Interface)

public abstract class Car {protected String color;protected String engine;public Car(String color, String engine) {this.color = color;this.engine = engine;}public abstract void show();
}

创建具体享元角色(Concrete Flyweight)

public class BMW extends Car {public BMW(String color, String engine) {super(color, engine);}@Overridepublic void show() {System.out.println("生产BMW汽车:颜色是" + color + ",发动机排量是" + engine);}
}
public class Benz extends Car{public Benz(String color, String engine) {super(color, engine);}@Overridepublic void show() {System.out.println("生产Benz汽车:颜色是" + color + ",发动机排量是" + engine);}
}

创建享元工厂角色(Flyweight Factory)

import java.util.HashMap;
import java.util.Map;public class CarFactory {public static Map<String, Car> carMap=new HashMap<>();public static Car getCar(String color,String type){String key=color+"_"+type;if(carMap.containsKey(key)){//如果已经有该颜色和类型的汽车,直接返回return carMap.get(key);}else {Car car = null;//没有,创建并放入缓存if("BMW".equals(type)){car = new BMW(color,"2.0L");}else if ("Benz".equals(type)){car = new Benz(color,"2.0L");}else {System.out.println("没有该类型的汽车");}//放入缓存carMap.put(key,car);return car;}}
}

创建客户端(Client)

public class Client {public static void main(String[] args) {Car bmwCar = CarFactory.getCar("白色", "BMW");Car benzCar = CarFactory.getCar("白色", "Benz");bmwCar.show();benzCar.show();System.out.println("现在已存在有" + CarFactory.carMap.size() + "种类型的汽车,及共享的相同对象");System.out.println("===================================");System.out.println("创建上面创建过的相同颜色和类型的汽车");Car bmwCar2 = CarFactory.getCar("白色", "BMW");bmwCar2.show();System.out.println("创建相同颜色和类型的汽车后,现在已存在有" + CarFactory.carMap.size() + "种类型的汽车,及共享的相同对象");System.out.println("===================================");System.out.println("创建上面没有添加过的颜色的汽车");Car bmwCar3 = CarFactory.getCar("黑色", "BMW");bmwCar3.show();System.out.println("创建不同的颜色,相同类型的汽车后,现在已存在有" + CarFactory.carMap.size() + "种类型的汽车,及共享的相同对象");}
}

输出结果如下所示:

生产BMW汽车:颜色是白色,发动机排量是2.0L
生产Benz汽车:颜色是白色,发动机排量是2.0L
现在已存在有2种类型的汽车,及共享的相同对象
===================================
创建上面创建过的相同颜色和类型的汽车
生产BMW汽车:颜色是白色,发动机排量是2.0L
创建相同颜色和类型的汽车后,现在已存在有2种类型的汽车,及共享的相同对象
===================================
创建上面没有添加过的颜色的汽车
生产BMW汽车:颜色是黑色,发动机排量是2.0L
创建不同的颜色,相同类型的汽车后,现在已存在有3种类型的汽车,及共享的相同对象

在上述例子中,我们共享了Car类,并在创建Car类时,设置了不同颜色。虽然我们创建了多次小汽车,但它们相同颜色和相同发动机排量的共享同一个享元对象,因此创建相同相同颜色和相同发动机排量的汽车时,可以减少了内存占用。

总而言之:
享元模式是一种用于优化性能的软件设计模式,它通过共享对象来减少内存中对象的数量,从而降低内存消耗并提高系统性能。该模式主要适用于大量相似对象、对象创建成本较高、需要精细化控制对象共享、大数据量处理、高并发以及分布式系统中的对象共享等场景。享元模式的优点包括减少内存消耗、提高性能以及支持大量细粒度对象。然而,它也可能增加编程的复杂性,并可能引入线程安全问题。因此,在选择使用享元模式时,需要仔细评估其适用性和潜在影响。享元模式是一种非常有用的设计模式,可以帮助我们优化系统性能并减少内存消耗。但是,它也需要在具体场景下仔细考虑和权衡利弊,确保正确使用并带来实际的效益。


以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git

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

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

相关文章

2024.3.20力扣每日一题——数组元素的最小非零乘积

2024.3.20 题目来源我的题解方法一 贪心 题目来源 力扣每日一题&#xff1b;题序&#xff1a;1969 我的题解 方法一 贪心 采用贪心&#xff0c;使得最终的序列应该是满足除了二进制位全为1的 2 p − 1 2^p-1 2p−1之外&#xff0c;其余的首尾两两配对进行交换&#xff0c;最…

docker安装nacos,单例模式(standalone),使用mysql数据库

文章目录 前言安装创建文件夹"假装"安装一下nacos拷贝文件夹删除“假装”安装的nacos容器生成nacos所需的mysql表获取mysql-schema.sql文件创建一个mysql的schema 重新生成新的nacos容器 制作docker-compose.yaml文件查看网站 前言 此处有本人写得简易版本安装&…

log4j 集成 ELK环境搭建

一、前言 1.需要准备一台linux服务器&#xff08;最好是CentOS7&#xff09;,内存至少4g以上&#xff08;三个组件都比较占用内存&#xff09; 2.需要有docker使用经验 3. 三个软件的版本要一致 二、安装ElasticSearch 这里先创建一个网络&#xff1a;因为我们还需要部署k…

VS2022编译OpenCV库(静态库和动态库)

OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方…

品牌定位升级|飞雕开关如何从家庭作坊走上国际之路?

飞雕电器,这个名字在中国开关插座行业中如同一面旗帜,自1987年起就扬帆在电工领域的大海中。它不仅见证了这个行业的起起伏伏,还始终以其创新的姿态站在浪尖之上。 飞雕的产品线丰富多彩,除主营的墙壁开关插座领域外,飞雕电器还涉足了与墙壁开关紧密相关的其它领域,现已推出移…

蓝桥杯第十四届C++C组

目录 三国游戏 填充 翻转 【单调队列优化DP】子矩阵 【快速幂、欧拉函数】互质数的个数 【tire树】异或和之差 【质因数分解】公因数匹配 子树的大小 三国游戏 题目描述 小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都…

Linux中安装nacos

Linux中安装nacos 一、前言二、准备1、下载2、上传到服务器3、解压 三、配置1、备份配置文件2、导入sql3、修改前4、修改后 四、使用1、启动2、关闭 一、前言 最近国外的docker似乎是出什么问题&#xff0c;试过很多手段都拉不下 nacos 镜像&#xff0c;就打算在服务器装一下 …

windows git bash 报错 bash: gh: command not found,需要安装 github的做桌面版工具 或者换成git 命令

需要安装 github的做桌面版工具 或者换成git 命令 git clone https://.........git 当你在 Windows 的 Git Bash 中遇到错误 bash: gh: command not found 时&#xff0c;这表示 Git Bash 无法识别 gh 命令。gh 命令是 GitHub 命令行工具的一部分&#xff0c;它提供了从命令行与…

能否安全地删除 Mac 资源库中的文件?

在管理Mac电脑存储空间时&#xff0c;用户确实可能考虑对资源库&#xff08;Library&#xff09;文件夹进行清理以释放空间。Mac资源库是一个系统及应用程序存放重要支持文件的地方&#xff0c;其中包括但不限于配置文件、临时文件、缓存、插件、偏好设置、应用程序支持数据等。…

ModuleNotFoundError: No module named ‘xxx.xx‘; ‘xxx‘ is not a package

ModuleNotFoundError: No module named sqllineage.runner; sqllineage is not a package 数据血缘关系使用python3安装了sqllineage&#xff0c;在执行python脚本时始终报错sqllineage is not a package&#xff0c;经过检查python3安装配置没问题&#xff0c;并且sqllineage…

Rustdesk二次编译,新集成AI功能开源Gpt小程序为远程协助助力,全网首发

环境&#xff1a; Rustdesk1.1.9 sciter版 问题描述&#xff1a; Rustdesk二次编译&#xff0c;新集成AI功能开源Gpt小程序为远程协助助力,全网首发 解决方案&#xff1a; Rustdesk二次编译&#xff0c;新集成开源AI功能Gpt小程序&#xff0c;为远程协助助力&#xff0c…

c语言中有哪些格式说明符,在scanf 会在遇到空白字符(空格、制表符或换行符)时停止读取(即scanf会忽略空格)

在C语言的 scanf 函数中&#xff0c;有几个格式说明符在遇到空白字符&#xff08;包括空格、制表符和换行符&#xff09;时会停止读取。这些格式说明符通常用于读取特定类型的输入数据。以下是一些常用的格式说明符&#xff1a; 1.%d 或 %i&#xff1a;用于读取整数。当 scanf …

【蓝桥杯嵌入式】六、真题演练(三)-2研究篇:第13届第一场真题

温馨提示&#xff1a; 真题演练分为模拟篇和研究篇。本专栏的主要作用是记录我的备赛过程&#xff0c;我打算先自己做一遍&#xff0c;把遇到的问题和不同之处记录到演练篇&#xff0c;然后再返回来仔细研究一下&#xff0c;找到最佳的解题方法记录到研究篇。题目在&#xff1a…

远程过程调用(远程调用)

远程过程调用&#xff08;远程调用&#xff09; 1、什么是分布式计算 在计算机科学中&#xff0c;分布式计算&#xff08;英语&#xff1a;Distributed computing&#xff09;&#xff0c;又译为分散式运算。这个研究领域&#xff0c;主要研究分布式系统&#xff08;Distribu…

学习周报:文献阅读+Fluent案例+水力学理论学习

目录 摘要 Abstract 文献阅读&#xff1a;物理信息的神经网络与湍流传质的非封闭机制模型相结合 文献摘要 提出问题 提出方案 实验设置 所需方程介绍 雷诺时均方程&#xff08;RANS&#xff09; K-epsilon两方程模型 神经网络框架 DNN部分 损失函数定义 PINN部分…

Francek Chen 的128天创作纪念日

目录 Francek Chen 的128天创作纪念日机缘收获日常成就憧憬 Francek Chen 的128天创作纪念日 Francek Chen 的个人主页 机缘 不知不觉的加入CSDN已有两年时间了&#xff0c;最初我第一次接触CSDN技术社区是在2022年4月的时候&#xff0c;通过学长给我们推荐了几个IT社区平台&a…

【Python】还在用print进行调试,你Out了!!!

1. 引言 Python 中最常用的函数是什么&#xff1f;像在大多数编程语言中&#xff0c;print() 函数是最常用的。我相信大多数开发者都会像我一样&#xff0c;在开发过程中多次使用它将信息进行打印。 当然&#xff0c;没有其他方法可以完全取代print()函数。不过&#xff0c;当…

系统架构设计基础知识

一. 系统架构概述系统架构的定义 系统架构&#xff08;System Architecture&#xff09;是系统的一种整体的高层次的结构表示&#xff0c;是系统的骨架和根基&#xff0c;支撑和链接各个部分&#xff0c;包括构件、连接件、约束规范以及指导这些内容设计与演化的原理&#xff0…

机电一体化系统设计学习笔记——接口技术和机电一体化

一、接口 1. 定义 是指连接机电一体化系统中不同部件、设备或软件模块之间的边界&#xff0c;使它们能够相互通信、交换信息或共享资源的一种技术手段。 2.作用 实现系统间的通信&#xff1a;接口技术使得机电一体化系统中的各个部件能够进行数据交换和通信&#xff0c;实现…

产品经理功法修炼(5)之团队管理

点击下载《产品经理功法修炼(5)之团队管理》 产品经理功法修炼(1)之自我管理 产品经理功法修炼(2)之专业技能 产品经理功法修炼(3)之产品设计 产品经理功法修炼(4)之产品管理 产品经理功法修炼(5)之团队管理 1. 前言 产品经理的能力修炼并非局限于某一技能的…