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

Java 设计模式——享元模式

目录

  • 1.概述
  • 2.结构
  • 3.实现
    • 3.1.抽象享元
    • 3.2.具体享元
    • 3.3.享元工厂
    • 3.4.测试
  • 4.优缺点
  • 5.使用场景
  • 6.JDK 源码解析——Integer 类

1.概述

(1)享元模式 (Flyweight Pattern) 是一种结构型设计模式,主要通过共享对象来减少系统中的对象数量,从而提高系统的性能。具体来说,享元模式是通过将对象分成内部状态外部状态两种形式来实现共享:

  • 内部状态:即不会随着环境的改变而改变的可共享部分。
  • 外部状态:指随环境改变而改变的不可以共享的部分。

通过将内部状态拆分出来,并且在一个对象池中创建对象时,判断是否已经存在需要创建的对象并返回已有对象,从而避免重复创建。

(2)这种模式适用于具有大量相近对象的场景,通过对象共享的方式可以大幅度减少系统的内存开销。在实际应用中,享元模式经常与其他设计模式相结合使用,以达到更好的效果。

2.结构

享元模式的主要有以下角色:

  • 抽象享元 (Flyweight) 角色:通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。
  • 具体享元 (Concrete Flyweight) 角色:它实现了抽象享元类,称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。
  • 非享元 (Unsharable Flyweight) 角色:并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
  • 享元工厂 (Flyweight Factory) 角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

3.实现

【例】俄罗斯方块:下面的图片是众所周知的俄罗斯方块中的一个个方块,如果在俄罗斯方块这个游戏中,每个不同的方块都是一个实例对象,这些对象就要占用很多的内存空间,下面利用享元模式进行实现。

在这里插入图片描述

类图如下:
在这里插入图片描述
具体实现代码如下:

3.1.抽象享元

AbstractBox.java

//抽象享元角色
public abstract class AbstractBox {//获取图形的方法public abstract String getShape();//显示图形以及颜色public void display(String color) {System.out.println("方块形状: " + getShape() + ": " + color);}
}

3.2.具体享元

IBox.java

public class IBox extends AbstractBox{@Overridepublic String getShape() {return "I";}
}

LBox.java

public class LBox extends AbstractBox{@Overridepublic String getShape() {return "L";}
}

OBox.java

public class OBox extends AbstractBox{@Overridepublic String getShape() {return "O";}
}

3.3.享元工厂

BoxFactory.java

//工厂类,将该类设计为单例
public class BoxFactory {private HashMap<String,AbstractBox> map;//在构造方法中进行初始化操作private BoxFactory(){map = new HashMap<String,AbstractBox>();map.put("I", new IBox());map.put("L", new LBox());map.put("O", new OBox());}private static BoxFactory factory = new BoxFactory();//提供一个方法获取该工厂类对象public static BoxFactory getInstance(){return factory;}//根据名称获取图形对象public AbstractBox getShape(String name){return map.get(name);}
}

3.4.测试

Client.java

public class Client {public static void main(String[] args) {//获取 I 图形对象AbstractBox box1 = BoxFactory.getInstance().getShape("I");box1.display("灰色");//获取 L 图形对象AbstractBox box2 = BoxFactory.getInstance().getShape("L");box2.display("红色");//获取 O 图形对象AbstractBox box3 = BoxFactory.getInstance().getShape("O");box3.display("黑色");//获取 O 图形对象AbstractBox box4 = BoxFactory.getInstance().getShape("O");box4.display("蓝色");System.out.println("两次获取到的 O 图形对象是否为同一个对象?" + (box3 == box4));}
}

输出结果如下:

方块形状: I: 灰色
方块形状: L: 红色
方块形状: O: 黑色
方块形状: O: 蓝色
两次获取到的 O 图形对象是否为同一个对象?true

4.优缺点

(1)享元模式的优点:

  • 减少内存使用:通过共享对象,减少了系统中的对象数量,从而节省了内存空间。
  • 提升性能:由于减少了对象的数量,可以提高系统的性能。共享的对象可以在多个上下文中共享使用,避免了重复创建对象的开销。
  • 简化操作:对于具有相同或相似内部状态的对象,可以共享一个享元对象,简化了对对象的操作。

(2)享元模式的缺点:

  • 共享对象状态的限制:由于享元模式需要将对象的内部状态和外部状态分离,因此可能会引入一定的限制。对于外部状态的改变,需要在外部进行设置,可能会带来一些额外的复杂性。
  • 对象共享的线程安全问题:如果多个线程同时使用享元对象,需要保证线程安全,避免对共享对象进行修改导致其他线程的错误结果。
  • 可能引入过多的复杂性:在使用享元模式时需要权衡对象的共享和不共享状态,可能会增加代码的复杂性和维护成本。

5.使用场景

(1)享元模式通常适用于以下场景:

  • 需要大量创建相似的对象:例如,用于图形编辑器中的大量相似图形元素(如矩形、圆形等),可以创建一个共享的图形元素对象池,避免每次创建图形元素时都进行对象的初始化,从而提高性能和减少内存占用。
  • 对象可以被共享复用:当一个对象需要在多个地方进行共享使用时,使用享元模式可以避免重复创建对象的开销,并且提高系统性能。
  • 对象的大部分状态可以外部化:如果一个对象的大部分状态可以被外部计算或者设置,可以使用享元模式来将内部状态与外部状态分离,避免重复创建对象的开销。
  • 系统需要缓存对象的场景:当系统需要缓存一些对象,并根据需要重复使用这些对象时,使用享元模式可以减少内存的使用,提高系统的性能。

(2)总之,享元模式适用于需要大量创建相似对象的场景,并且这些对象可以被共享复用,可以提高系统的性能和减少内存占用。

6.JDK 源码解析——Integer 类

相关面试题可以参考下面的文章:
Java 基础面试题——基本数据类型与包装类

Integer 类使用了享元模式。先看下面的例子:

class IntegerDemo {public static void main(String[] args) {Integer i1 = 127;Integer i2 = 127;System.out.println("i1 和 i2 是否为同一个对象?" + (i1 == i2));Integer i3 = 128;Integer i4 = 128;System.out.println("i3 和 i4 是否为同一个对象?" + (i3 == i4));}
}

上述程序的运行结果如下:

i1 和 i2 是否为同一个对象?true
i3 和 i4 是否为同一个对象?false

为什么第一个输出语句输出的是 true,第二个输出语句输出的是 false?通过反编译软件进行反编译,代码如下:

public class Demo {public static void main(String[] args) {Integer i1 = Integer.valueOf((int)127);Integer i2 Integer.valueOf((int)127);System.out.println((String)new StringBuilder().append((String)"i1\u548ci2\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f").append((boolean)(i1 ==i2)).toString());Integer i3 = Integer.valueOf((int)128);Integer i4 = Integer.valueOf((int)128);System.out.println((String)new StringBuilder().append((String)"i3\u548ci4\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f").append((boolean)(i3 ==i4)).toString());}
}

从上面代码可以看出,直接给 Integer 类型的变量赋值的底层操作使用方法的是 valueOf(),所以只需看该方法的代码即可:

public final class Integer extends Number implements Comparable<Integer> {//...public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {int h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}
}

可以看到 Integer 默认先创建并缓存 -128 ~ 127 之间数的 Integer 对象,当调用 valueOf() 方法时:

  • 如果参数在 -128 ~ 127 之间则计算下标并从缓存中返回;
  • 否则创建一个新的 Integer 对象。

相关文章:

Java 设计模式——享元模式

目录 1.概述2.结构3.实现3.1.抽象享元3.2.具体享元3.3.享元工厂3.4.测试 4.优缺点5.使用场景6.JDK 源码解析——Integer 类 1.概述 &#xff08;1&#xff09;享元模式 (Flyweight Pattern) 是一种结构型设计模式&#xff0c;主要通过共享对象来减少系统中的对象数量&#xff…...

再扩国产化适配版图,长安链新增数据库兼容性认证

基础软件的自主可控影响着国家信息安全与产业技术发展是否受制于人。实现真正长期可持续的技术自主可控&#xff0c;需要再进一步的是让国产化信息系统生态更有”活性“&#xff0c;基础软件之间、基础软件与其他国产上层应用的互相兼容、互相促进&#xff0c;共同繁荣发展&…...

MES系统数据集成系统源码

MES系统数据集成系统源码 1 MES的生产计划管理综述 生产计划的管理在MES系统中是非常重要的。我们知道&#xff0c;一般的情况下&#xff0c;企业的生产计划是由上层管理系统ERP来完成&#xff0c;那么MES中的生产计划和ERP的生产计划的不同点在于&#xff1a; ERP的生产计划…...

关于道一云-七巧使用感悟

低代码&#xff0c;开发快速&#xff0c;缺点组件比较少但能满足大多数场景&#xff0c;如果需要的话得自己造&#xff0c;官方的技术群里面普遍问题响应就很快&#xff0c;技术文档这个会抽风&#xff0c;有些代码就改个筛选条件本地死活运行不了&#xff0c;去官网那里问他们…...

去中心化数据云项目Oort主网即将上线

备受期待的去中心化数据云项目Oort&#xff0c;今日已通过官方X账号官宣&#xff0c;将于纽约时间11月27日正式上线主网Olympus Protocol。届时&#xff0c;用户也能够通过Oort的Ale Wallet钱包和开发者API使用主网&#xff0c;并可通过OORT浏览器查询交易和合约&#xff0c;开…...

CSS知识点梳理(一)

CSS 是层叠样式表&#xff08;Cascading Style Sheets&#xff09;的缩写&#xff0c;它是一种用于描述 HTML 或 XML&#xff08;包括如 SVG、MathML 等派生语言&#xff09;文档呈现的语言。CSS 可以用来控制文档的布局、颜色、字体等外观属性。 CSS 的主要特点包括&#xff…...

网络安全深入学习第八课——反向代理(工具:frp)

文章目录 一、实验环境二、实验要求三、开始模拟1、攻击机配置frp文件2、攻击拿下跳板机&#xff0c;并且上传frpc.ini、frpc.exe、frpc_full.ini文件3、把frps.ini、、frps.exe、frps_full.ini文件放到VPS主机上4、VPS机开启frp5、跳板机开启frp6、验证 一、实验环境 攻击机&…...

浅谈前端自定义VectorGrid矢量瓦片样式

目录 前言 一、VectorGrid相关API介绍 1、VectorGrid 2、 LayerStyles样式详解 二、样式自动配置 1、页面定义 2、地图及PBF瓦片引入 3、矢量瓦片样式定义 4、鼠标事件交互 三、最终效果 1、自定义样式展示 2、鼠标交互 总结 前言 在上一篇博客中&#xff0c;详细讲…...

Qt5多线程<12>

1.多线程的简单实现 <1> 在头文件threaddlg.h声明用于界面显示所需的控件,其代码如下: #ifndef THREADDLG_H #define THREADDLG_H#include <QDialog> #include <QPushButton> #include "workthread.h" #define MAXSIZE 5class ThreadDlg : publ…...

Linux学习笔记之五(父子进程、孤儿进程、僵尸进程、守护进程)

Linux 1、进程1.1、进程的六种状态1.2、创建子进程1.3、添加子进程任务1.4、孤儿进程、僵尸进程、守护进程1.4.1、避免僵尸进程1.4.2、创建守护进程1.4.3、杀死守护进程 1.5、综合练习 1、进程 进程可以简单的理解为一个正在执行的程序&#xff0c;它是计算机系统中拥有资源和…...

[题] 不容易系列之(3)―― LELE的RPG难题 #DP

题目 不容易系列之(3)―― LELE的RPG难题 思路 简单的DP题。 代码 #include<bits/stdc.h> using namespace std; //默认以0开头&#xff0c;以1和2结尾。f[i][1]表示长度为i的以1结尾的涂抹方案 //状态转移方程&#xff1a;若以1结尾&#xff0c;则前面一个格子只能是…...

pip 安装任意软件包报错

现象 使用 pip 命令时提示 查看源码 可以看到是从 pip 包中导入 main失败&#xff0c;点击查看目录 main 文件不见了&#xff0c;判断是文件缺失&#xff0c;重装 pip 即可 # python3 下载 pip curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py # python2 下载…...

NLP之Bert实现文本多分类

文章目录 代码代码整体流程解读debug上面的代码 代码 from pypro.chapters03.demo03_数据获取与处理 import train_list, label_list, val_train_list, val_label_list import tensorflow as tf from transformers import TFBertForSequenceClassificationbert_model "b…...

对话大众软件子公司:中国的智舱、智驾比欧洲早一代

作者 | 德新 编辑 | 王博 尤其在上海车展之后&#xff0c;大部分的外资车企都在转型调整。 2023年的上海车展是一个重要节点。在这之前&#xff0c;疫情阻断了国内和海外频繁的线下交流&#xff0c;而国内汽车的新能源化和智能化在这期间完成了一次飞跃式的发展。所以车展开…...

基于FPGA的图像RGB转HSV实现,包含testbench和MATLAB辅助验证程序

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1. RGB与HSV色彩空间 4.2. RGB到HSV转换原理 5.算法完整程序工程 1.算法运行效果图预览 将FPGA的仿真结果导入到matlab中&#xff1a; 2.算法运行软件版本 vivado2019.2 matlab2022a …...

小型企业如何数字化转型?ZohoCRM助力小企业转型

小型企业数字化之路倍加艰难&#xff0c;其组织规模有限、资源有限&#xff0c;数字化布局或转型&#xff0c;也存在与数字平台匹配度的问题。其实小型企业可以通过CRM客户管理系统实现高效的客户关系管理&#xff0c;进一步提高市场竞争力。 建立高效易用的客户关系管理系统 …...

聊聊模板引擎<Template engine>

模板引擎是什么 模板引擎是一种用于生成动态内容的工具&#xff0c;通常用于Web开发中。它能够将静态的模板文件和动态数据结合起来&#xff0c;生成最终的HTML、XML或其他文档类型。模板引擎通过向模板文件中插入变量、条件语句、循环结构等控制语句&#xff0c;从而实现根据…...

多平台商品采集——API接口:支持淘宝、天猫、1688、拼多多等多个电商平台的爆款、销量、整店商品采集和淘客功能

item_get-获得淘宝商品详情 item_get_app-获得淘宝app商品详情原数据 item_get_pro-获得淘宝商品详情高级版 item_search-按关键字搜索淘宝商品 item_search_img-按图搜索淘宝商品&#xff08;拍立淘&#xff09; item_search_shop-获得店铺的所有商品 API请求地址 公共…...

UI自动化测试框架设计(Selenium)

...

towr code阅读

1. Introduction towr是非常优美的足式机器人规划代码&#xff0c;通过阅读towr重要的几个迭代版本的代码深入了解。 2 v0.1 第一代的版本&#xff0c;foot的位置是提前给定的&#xff0c;只对COG的trajectory进行优化。 2.1 cost 公式 仅仅只考虑加速度&#xff0c; ∫ …...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

一些实用的chrome扩展0x01

简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序&#xff0c;无论是测试应用程序、搜寻漏洞还是收集情报&#xff0c;它们都能提升工作流程。 FoxyProxy 代理管理工具&#xff0c;此扩展简化了使用代理&#xff08;如 Burp…...

Python常用模块:time、os、shutil与flask初探

一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...

当下AI智能硬件方案浅谈

背景&#xff1a; 现在大模型出来以后&#xff0c;打破了常规的机械式的对话&#xff0c;人机对话变得更聪明一点。 对话用到的技术主要是实时音视频&#xff0c;简称为RTC。下游硬件厂商一般都不会去自己开发音视频技术&#xff0c;开发自己的大模型。商用方案多见为字节、百…...

在Spring Boot中集成RabbitMQ的完整指南

前言 在现代微服务架构中&#xff0c;消息队列&#xff08;Message Queue&#xff09;是实现异步通信、解耦系统组件的重要工具。RabbitMQ 是一个流行的消息中间件&#xff0c;支持多种消息协议&#xff0c;具有高可靠性和可扩展性。 本博客将详细介绍如何在 Spring Boot 项目…...