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

享元模式(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)

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

Oracle连接mysql

oracle使用的11g&#xff0c;在一台windows服务器&#xff1b;mysql使用的是5.7版本&#xff0c;在另一台windows服务器&#xff0c;这两个服务器之间的网络是互通的。做BI时&#xff0c;要获取不同数据源的数据&#xff0c;这些数据源可能是Oracle&#xff0c;也可能是sqlserv…...

golang 垃圾回收

gc不回收什么 GC 不负责回收栈中的内存栈是一块专用内存&#xff0c;专门为了函数执行而准备的&#xff0c;存储着函数中的局部变量以及调用栈栈中的数据可以通过简单的编译器指令自动清理&#xff0c;也就不需要通过 GC 来回收了 垃圾回收算法 主流的两类垃圾回收算法有两种&a…...

React 中如何使用 Monaco

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

开源RAG个人知识库项目开发分析

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

事务底层与高可用原理

1.事务底层与高可用原理 事务的基础知识 mysql的事务分为显式事务和隐式事务 默认的事务是隐式事务 显式事务由我们自己控制事务的开启&#xff0c;提交&#xff0c;回滚等操作 show variables like autocommit; 事务基本语法 事务开始 1、begin 2、START TRANSACTION&…...

树状数组基础知识

lowbit: lowbit(x)x&(-x) 树状数组&#xff1a; 树状数组的功能&#xff1a; 数组 在O(1)的时间复杂度实现单点加&#xff1a; 在O(lng n)的时间复杂度实现查询前缀和&#xff1a; 树状数组的定义&#xff1a; 查询前x项的和操作&#xff1a; ll query(int x){ll s0;f…...

【3分钟准备前端面试】vue3

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

【数据采集】亮数据浏览器、亮网络解锁器实战指南

前言 继上次我们写了数据采集与AI分析&#xff0c;亮数据通义千问助力跨境电商前行的文章之后&#xff0c;好多小伙伴来后台留言&#xff0c;表示对亮数据的数据采集非常感兴趣&#xff0c;并且感觉用起来非常顺手&#xff0c;大大减少了小白用户获取数据的成本。 在这儿&…...

暑期编程预习指南

暑期编程预习指南 高考结束后&#xff0c;迎来的是一段难得的假期时光。对于那些有志于踏入IT领域的高考生来说&#xff0c;这段时间无疑是一个重要的起点。为了帮助你们更好地利用这个假期&#xff0c;为未来的学习和职业生涯打下坚实的基础&#xff0c;特此提供一份编程预习…...

将带有 商店idr 商品信息的json导入到mongodb后,能不能根据商店id把所有商品全部提取并转为电子表格

当您已经将包含商店ID&#xff08;如realMallId&#xff09;的商品信息导入MongoDB后&#xff0c;确实可以轻松地根据商店ID提取所有相关商品信息并转换为电子表格&#xff08;例如Excel&#xff09;。这里是一个简化的流程&#xff0c;使用Python的pymongo库来查询MongoDB&…...

深入解析 androidx.databinding.BaseObservable

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

MySQL数据恢复(适用于误删后马上发现)

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

[数据结构】——七种常见排序

文章目录 前言 一.冒泡排序二.选择排序三.插入排序四.希尔排序五.堆排序六.快速排序hoare挖坑法前后指针快排递归实现&#xff1a;快排非递归实现&#xff1a; 七、归并排序归并递归实现&#xff1a;归并非递归实现&#xff1a; 八、各个排序的对比图 前言 排序&#xff1a;所谓…...

CPU占用率飙升至100%:是攻击还是正常现象?

在运维和开发的日常工作中&#xff0c;CPU占用率突然飙升至100%往往是一个令人紧张的信号。这可能意味着服务器正在遭受攻击&#xff0c;但也可能是由于某些正常的、但资源密集型的任务或进程造成的。本文将探讨如何识别和应对服务器的异常CPU占用情况&#xff0c;并通过Python…...

java如何替换字符串中给定索引的字符

java如果要修改给定字符串的索引字符&#xff0c;需要用到setCharAt方法 它的语法格式是 sbf.setCharAt(index,ch) 其中&#xff1a; sbf是任意StringBuffer对象 index是被替换字符的索引 ch是替换后的索引 如果是修改一个字符就用这个方法。如果是批量修改&#xff0c;…...

基于RK3588的GMSL、FPDLink 、VByone及MIPI等多种摄像模组,适用于车载、机器人工业图像识别领域

机器人&工业摄像头 针对机器人视觉与工业检测视觉&#xff0c;信迈自主研发和生产GMSL、FPDLink 、VByone及MIPI等多种摄像模组&#xff0c;并为不同应用场景提供多种视场角度和镜头。拥有资深的图像算法和图像ISP专家团队&#xff0c;能够在软件驱动层开发、ISP算法、FPG…...

Windows 的 MFC开发的使用示例——讲得挺好的

【Visual Studio 2019】创建 MFC 桌面程序 ( 安装 MFC 开发组件 | 创建 MFC 应用 | MFC 应用窗口编辑 | 为按钮添加点击事件 | 修改按钮文字 | 打开应用 )-腾讯云开发者社区-腾讯云 (tencent.com)...

Spring4.3.x xml配置文件搜索和解析过程

###概述 这篇文章的研究不只是涉及到spring如何创建一个BeanDefinition对象&#xff0c;还涉及到spring如何加载文件、如何读取XML文件、以及我们在使用spring的时候如何扩展spring的配置。 spring在创建BeanFactory时会把xml配置文件和注解信息转换为一个个BeanDefinition对…...

网络爬虫(一)深度优先爬虫与广度优先爬虫

1. 深度优先爬虫&#xff1a;深度优先爬虫是一种以深度为优先的爬虫算法。它从一个起始点开始&#xff0c;先访问一个链接&#xff0c;然后再访问该链接下的链接&#xff0c;一直深入地访问直到无法再继续深入为止。然后回溯到上一个链接&#xff0c;再继续深入访问下一个未被访…...

卡证检测矫正模型中小企业降本:替代万元级专用证件扫描仪方案

卡证检测矫正模型&#xff1a;中小企业降本利器&#xff0c;替代万元级专用证件扫描仪方案 1. 引言&#xff1a;一个被忽视的降本痛点 如果你在中小企业负责行政、人事或财务&#xff0c;一定对下面这个场景不陌生&#xff1a;每天要处理一堆身份证、护照、驾照的复印件或扫描…...

深度探索:开源工具OpenCore Legacy Patcher技术揭秘与完整指南

深度探索&#xff1a;开源工具OpenCore Legacy Patcher技术揭秘与完整指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 随着苹果系统持续演进&#xff0c;…...

DeepSeek-V3.2量化新标杆:w8a8精度突破86%!

DeepSeek-V3.2量化新标杆&#xff1a;w8a8精度突破86%&#xff01; 【免费下载链接】DeepSeek-V3.2-w8a8-mtp-QuaRot 项目地址: https://ai.gitcode.com/Eco-Tech/DeepSeek-V3.2-w8a8-mtp-QuaRot 导语&#xff1a;DeepSeek-V3.2推出w8a8量化版本&#xff0c;采用创新Qu…...

Janus-Pro-7B入门编程教学:从零开始学习C语言文件读写操作

Janus-Pro-7B入门编程教学&#xff1a;从零开始学习C语言文件读写操作 你是不是刚开始学C语言&#xff0c;一看到文件操作就觉得头大&#xff1f;fopen、fwrite、fread这些函数名字看着就复杂&#xff0c;更别提什么文件指针、缓冲区这些概念了。别担心&#xff0c;这感觉我懂…...

告别混乱文件管理:用NERDTree打造VIM项目导航系统

告别混乱文件管理&#xff1a;用NERDTree打造VIM项目导航系统 每次打开一个包含数百个文件的复杂项目时&#xff0c;你是否会感到一阵眩晕&#xff1f;当你在多个目录间反复切换查找某个配置文件时&#xff0c;是否觉得时间在指尖悄然流逝&#xff1f;对于资深VIM用户而言&…...

[模电]从PN结到实用电路:二极管的深度解析与设计指南

1. PN结&#xff1a;二极管的物理基础 想象一下把一块P型半导体和N型半导体紧密贴合在一起&#xff0c;就像把两块不同颜色的橡皮泥揉捏在一起。P型半导体里充满了带正电的"空穴"&#xff08;可以理解为缺少电子的位置&#xff09;&#xff0c;而N型半导体则富含自由…...

零成本打造私有云盘:从PHPStudy安装到IPv6动态域名解析全攻略

零成本打造私有云盘&#xff1a;从PHPStudy安装到IPv6动态域名解析全攻略 在数字化时代&#xff0c;个人数据存储需求呈爆炸式增长。网盘限速、隐私泄露、订阅费用高昂等问题困扰着许多用户。本文将手把手教你如何利用闲置电脑和免费工具&#xff0c;打造一个完全由自己掌控的私…...

C++ 中this的秘密

class Test {public:void test() {test1();}void test1() {i = 10...

Flutter项目卡在‘assembleDebug’?Gradle配置优化全攻略

1. 为什么Flutter项目会卡在assembleDebug阶段&#xff1f; 这个问题困扰过无数Flutter开发者&#xff0c;尤其是刚入门的新手。当你满怀期待地运行flutter run命令&#xff0c;结果控制台卡在Running Gradle task assembleDebug...一动不动&#xff0c;那种感觉就像等一辆永远…...

手把手教你用Arm Cortex-A715手册:从RAS到调试,一份给芯片设计者的实战笔记

Cortex-A715实战指南&#xff1a;芯片设计者的RAS与调试技术精要 在当今高性能计算领域&#xff0c;Arm Cortex-A715处理器核心凭借其卓越的能效比和性能表现&#xff0c;已成为众多芯片设计项目的首选。本文将从工程实践角度&#xff0c;深入剖析Cortex-A715的两个关键子系统&…...