享元模式(Flyweight Pattern)
享元模式(Flyweight Pattern)
定义
享元模式通过共享技术来支持大量细粒度的对象,以减少内存中的对象数量。其核心思想是将对象的状态分为内部状态和外部状态,内部状态是不变的,可以被多个对象共享;外部状态是随环境改变而改变的,不能共享,必须由客户端保持。
属于结构型模式。
适用场景
- 系统有大量相似对象:这些对象除了几个参数外基本相同,可以通过共享来减少内存消耗。
- 需要缓冲池的场景:如数据库连接池、线程池等,通过共享对象池中的对象来提高资源利用率。
- 对象创建成本较高:创建对象的成本较高时,使用享元模式可以减少对象的创建数量,降低成本。
标准示例
Flyweight
抽象的享元角色
这是所有具体享元类的超类,为这些类规定出需要实现的公共接口。通常包含一些与内部状态相关的操作,这些内部状态是可以在多个享元对象之间共享的。
/*** 抽象享元角色*/
public interface IFlyweight {/*** 业务方法* @param extrinsicState 外在状态*/void operation(String extrinsicState);
}
ConcreteFlyweight
具体的享元角色
实现抽象享元角色所规定的接口。如果有内部状态的话,必须负责为内部状态提供存储空间。享元对象的内部状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。
/*** 具体享元角色*/
public class ConcreteFlyweight implements IFlyweight{//内在状态,内在状态不会改变private String intrinsicState;public ConcreteFlyweight(String intrinsicState){this.intrinsicState = intrinsicState;}/*** 业务方法* @param extrinsicState 外在状态*/public void operation(String extrinsicState) {System.out.println("Object address:" + System.identityHashCode(this));System.out.println("IntrinsicState:" + this.intrinsicState);System.out.println("ExtrinsicState:" + extrinsicState);}
}
FlyweightFactory
享元工厂角色
负责创建和管理享元角色。当客户端请求一个享元对象时,享元工厂会检查系统中是否已经存在适当的享元对象,如果存在则直接返回该对象,否则创建一个新的享元对象。
通常通过哈希表(如HashMap)来存储和管理享元对象,以提高对象的检索和创建效率。
/*** 享元工厂*/
public class FlyweightFactory {private static Map<String,IFlyweight> pool = new HashMap<String, IFlyweight>();//内部状态作为缓存的keypublic static IFlyweight getFlyweight(String intrinsicState){if (!pool.containsKey(intrinsicState)){IFlyweight flyweight = new ConcreteFlyweight(intrinsicState);pool.put(intrinsicState,flyweight);}return pool.get(intrinsicState);}
}
ClientTest
调用类:
public class ClientTest {public static void main(String[] args) {IFlyweight flyweight = FlyweightFactory.getFlyweight("黑桃A");flyweight.operation("地主出的");IFlyweight flyweight1 = FlyweightFactory.getFlyweight("黑桃A");flyweight1.operation("地主出过的");}
}
执行结果输出为:
Object address:1360875712
IntrinsicState:黑桃A
ExtrinsicState:地主出的
Object address:1360875712
IntrinsicState:黑桃A
ExtrinsicState:地主出过的
内部状态与外部状态:
享元模式的关键在于区分内部状态和外部状态。
内部状态是可以在多个对象中共享的,而外部状态是随环境改变而改变的,不能共享。
举一个下五子棋的例子。
棋子的颜色为内部状态:黑和白;
下棋坐标位置为外部状态:Point(x,y)
假设一局五子棋,黑白双方各落子30枚,如果不用享元,就要new 60个对象。
如果采用享元,只需要2个对象即可。
请看如下设计:
ChessPiece
棋子,作为抽象享元角色,包含了一个落子的方法 placingPiece(Point p)
/*** 抽象棋子*/
public interface ChessPiece {/*** 落子* @param point 落子坐标*/void placingPiece(Point point);
}
WhitePiece
白色棋子,是具体享元角色。
/*** 白色棋子*/
public class WhitePiece implements ChessPiece{private String color = "white";public void placingPiece(Point point) {System.out.println( color +" piece named "+System.identityHashCode(this) + ", placing on "+point.toString());}
}
BlackPiece
黑色棋子,是具体享元角色。
/*** 黑色棋子*/
public class BlackPiece implements ChessPiece{private String color = "black";public void placingPiece(Point point) {System.out.println( color +"piece named "+System.identityHashCode(this) + ", placing on "+point.toString());}
}
Point
是非享元角色,即外部状态。
/*** 棋盘坐标点*/
@Data
public class Point {private String x;private String y;public Point(String x,String y){this.x = x;this.y = y;}@Overridepublic String toString() {return "" +"x='" + x + '\'' +", y='" + y + '\'';}
}
GobangFactory
五子棋工厂,用来提供棋子。
/*** 五子棋工厂类*/
public class GobangFactory {private static Map<String,ChessPiece> pieces = new HashMap<String, ChessPiece>(2);public static ChessPiece getPiece(String color){if(!StringUtils.equalsAny(color,"black","white")){throw new UnsupportedOperationException("拿错棋子了!");}//如果map中还没有棋子,那么添加进去。if(!pieces.containsKey(color)){//如果是白色,就把白子加进mapif("white".equals(color)){ChessPiece piece =new WhitePiece();pieces.put("white",piece);}//如果是黑色,就把黑子加进mapif("black".equals(color)){ChessPiece piece =new BlackPiece();pieces.put("black",piece);}}//取子返回return pieces.get(color);}}
ClientPlay
调用类:
public class ClientPlay {public static void main(String[] args) {ChessPiece piece1 = GobangFactory.getPiece("white");piece1.placingPiece(new Point("10","20"));ChessPiece piece2 = GobangFactory.getPiece("black");piece2.placingPiece(new Point("10","30"));ChessPiece piece3 = GobangFactory.getPiece("white");piece3.placingPiece(new Point("20","40"));ChessPiece piece4 = GobangFactory.getPiece("black");piece4.placingPiece(new Point("20","50"));}
}
执行结果输出为:
white piece named 1725154839, placing on x='10', y='20'
blackpiece named 1670675563, placing on x='10', y='30'
white piece named 1725154839, placing on x='20', y='40'
blackpiece named 1670675563, placing on x='20', y='50'
以上为享元模式全部内容,感谢阅读。
相关文章:

享元模式(Flyweight Pattern)
享元模式(Flyweight Pattern) 定义 享元模式通过共享技术来支持大量细粒度的对象,以减少内存中的对象数量。其核心思想是将对象的状态分为内部状态和外部状态,内部状态是不变的,可以被多个对象共享;外部状…...

Oracle连接mysql
oracle使用的11g,在一台windows服务器;mysql使用的是5.7版本,在另一台windows服务器,这两个服务器之间的网络是互通的。做BI时,要获取不同数据源的数据,这些数据源可能是Oracle,也可能是sqlserv…...
golang 垃圾回收
gc不回收什么 GC 不负责回收栈中的内存栈是一块专用内存,专门为了函数执行而准备的,存储着函数中的局部变量以及调用栈栈中的数据可以通过简单的编译器指令自动清理,也就不需要通过 GC 来回收了 垃圾回收算法 主流的两类垃圾回收算法有两种&a…...

React 中如何使用 Monaco
Monaco 是微软开源的一个编辑器,VSCode 也是基于 Monaco 进行开发的。如果在 React 中如何使用 Monaco,本文将介绍如何在 React 中引入 Monaco。 安装 React 依赖 yarn add react-app-rewired --dev yarn add monaco-editor-webpack-plugin --dev yarn…...

开源RAG个人知识库项目开发分析
前言 Hello,大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者,这个LLM开发基础阶段已经进入尾声了,本文中我们不介绍更多的理论与知识点,而是通过的分析开源项目的解决方案来帮助各位开发者理…...

事务底层与高可用原理
1.事务底层与高可用原理 事务的基础知识 mysql的事务分为显式事务和隐式事务 默认的事务是隐式事务 显式事务由我们自己控制事务的开启,提交,回滚等操作 show variables like autocommit; 事务基本语法 事务开始 1、begin 2、START TRANSACTION&…...
树状数组基础知识
lowbit: lowbit(x)x&(-x) 树状数组: 树状数组的功能: 数组 在O(1)的时间复杂度实现单点加: 在O(lng n)的时间复杂度实现查询前缀和: 树状数组的定义: 查询前x项的和操作: ll query(int x){ll s0;f…...

【3分钟准备前端面试】vue3
目录 Vue3比vue2有什么优势vue3升级了哪些重要功能生命周期变化Options APIComposition APIreftoRef和toRefstoReftoRefsHooks (代码复用)Vue3 script setupsetupdefineProps和defineEmitsdefineExposeVue3比vue2有什么优势 性能更好体积更小更好的TS支持更好的代码组织更好的逻…...

【数据采集】亮数据浏览器、亮网络解锁器实战指南
前言 继上次我们写了数据采集与AI分析,亮数据通义千问助力跨境电商前行的文章之后,好多小伙伴来后台留言,表示对亮数据的数据采集非常感兴趣,并且感觉用起来非常顺手,大大减少了小白用户获取数据的成本。 在这儿&…...
暑期编程预习指南
暑期编程预习指南 高考结束后,迎来的是一段难得的假期时光。对于那些有志于踏入IT领域的高考生来说,这段时间无疑是一个重要的起点。为了帮助你们更好地利用这个假期,为未来的学习和职业生涯打下坚实的基础,特此提供一份编程预习…...
将带有 商店idr 商品信息的json导入到mongodb后,能不能根据商店id把所有商品全部提取并转为电子表格
当您已经将包含商店ID(如realMallId)的商品信息导入MongoDB后,确实可以轻松地根据商店ID提取所有相关商品信息并转换为电子表格(例如Excel)。这里是一个简化的流程,使用Python的pymongo库来查询MongoDB&…...

深入解析 androidx.databinding.BaseObservable
在现代 Android 开发中,数据绑定 (Data Binding) 是一个重要的技术,它简化了 UI 和数据之间的交互。在数据绑定框架中,androidx.databinding.BaseObservable 是一个关键类,用于实现可观察的数据模型。本文将详细介绍 BaseObservab…...

MySQL数据恢复(适用于误删后马上发现)
首先解释一下标题,之所以适用于误删后马上发现是因为太久了之后时间和当时操作的数据表可能会记不清楚,不是因为日志丢失 1.首先确保自己的数据库开启了binlog(我的是默认开启的我没有配置过) 根据这篇博客查看自己的配置和自己…...

[数据结构】——七种常见排序
文章目录 前言 一.冒泡排序二.选择排序三.插入排序四.希尔排序五.堆排序六.快速排序hoare挖坑法前后指针快排递归实现:快排非递归实现: 七、归并排序归并递归实现:归并非递归实现: 八、各个排序的对比图 前言 排序:所谓…...
CPU占用率飙升至100%:是攻击还是正常现象?
在运维和开发的日常工作中,CPU占用率突然飙升至100%往往是一个令人紧张的信号。这可能意味着服务器正在遭受攻击,但也可能是由于某些正常的、但资源密集型的任务或进程造成的。本文将探讨如何识别和应对服务器的异常CPU占用情况,并通过Python…...
java如何替换字符串中给定索引的字符
java如果要修改给定字符串的索引字符,需要用到setCharAt方法 它的语法格式是 sbf.setCharAt(index,ch) 其中: sbf是任意StringBuffer对象 index是被替换字符的索引 ch是替换后的索引 如果是修改一个字符就用这个方法。如果是批量修改,…...

基于RK3588的GMSL、FPDLink 、VByone及MIPI等多种摄像模组,适用于车载、机器人工业图像识别领域
机器人&工业摄像头 针对机器人视觉与工业检测视觉,信迈自主研发和生产GMSL、FPDLink 、VByone及MIPI等多种摄像模组,并为不同应用场景提供多种视场角度和镜头。拥有资深的图像算法和图像ISP专家团队,能够在软件驱动层开发、ISP算法、FPG…...
Windows 的 MFC开发的使用示例——讲得挺好的
【Visual Studio 2019】创建 MFC 桌面程序 ( 安装 MFC 开发组件 | 创建 MFC 应用 | MFC 应用窗口编辑 | 为按钮添加点击事件 | 修改按钮文字 | 打开应用 )-腾讯云开发者社区-腾讯云 (tencent.com)...
Spring4.3.x xml配置文件搜索和解析过程
###概述 这篇文章的研究不只是涉及到spring如何创建一个BeanDefinition对象,还涉及到spring如何加载文件、如何读取XML文件、以及我们在使用spring的时候如何扩展spring的配置。 spring在创建BeanFactory时会把xml配置文件和注解信息转换为一个个BeanDefinition对…...

网络爬虫(一)深度优先爬虫与广度优先爬虫
1. 深度优先爬虫:深度优先爬虫是一种以深度为优先的爬虫算法。它从一个起始点开始,先访问一个链接,然后再访问该链接下的链接,一直深入地访问直到无法再继续深入为止。然后回溯到上一个链接,再继续深入访问下一个未被访…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...