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

享元模式-提供统一实现对象的复用

 下围棋时,分为黑白棋子。棋子都一样,这是出现的位置不同而已。如果将每个棋子都作为一个独立的对象存储在内存中,将导致内存空间消耗较大。我们可以将其中不变的部分抽取出来,只存储它的位置信息来实现节约内存。

 图 围棋

1 享元模式概述

通过共享技术实现相同或相似对象重用。做到共享的关键是区分“内部状态”和“外部状态”。

  1. 内部状态:是存储在享元内部并且不会随着环境改变而改变的状态,内部状态可共享。比如围棋的颜色属性。
  2. 外部状态:是随着环境改变而改变的、不可共享的状态。外部状态通常由客户端保存,并且在享元对象被创建之后,需要使用的时候,再传入享元对象的内部。一个外部状态与另一个外部状态之间是相互独立的。比如围棋的位置属性。

图 享元模式结构图

Flyweight: 抽象享元类,通常是一个接口或抽象类。声明的方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(状态)。

ConcreteFlyweight: 具体享元类,其实例称为享元对象。为内部状态提供了存储空间。通常可以结合单例模式来设计具体享元类。

UnsharedConcreteFlyweight: 非共享具体享元类。并不是所有抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类。当需要一个非共享具体享元对象时,可以直接通过实例化创建。

FlyweightFactory: 享元工厂类,用于创建并管理享元对象,针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中。

public class Coordinate {private int x;private int y;public Coordinate(int x, int y) {this.x = x;this.y = y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}@Overridepublic String toString() {return "{" +"x=" + x +", y=" + y +'}';}
}
public abstract class AbstractChess {public abstract String getColor();public void display(Coordinate coordinate) {System.out.println(getColor() + "落在" + coordinate);}}public class BlackChess extends AbstractChess{@Overridepublic String getColor() {return "黑棋";}private BlackChess() {}private static class ClassHolder {private static final BlackChess instance = new BlackChess();}public static BlackChess getInstance() {return ClassHolder.instance;}}public class WhiteChess extends AbstractChess{@Overridepublic String getColor() {return "白棋";}private WhiteChess() {}private static class ClassHolder {private static final WhiteChess instance = new WhiteChess();}public static WhiteChess getInstance() {return ClassHolder.instance;}}public class Client {// 存储外部状态(棋子的位置)private static final List<Coordinate> whiteCoordinateList = new ArrayList<>();private static final List<Coordinate> blackCoordinateList = new ArrayList<>();static {whiteCoordinateList.add(new Coordinate(1,4));whiteCoordinateList.add(new Coordinate(2,3));whiteCoordinateList.add(new Coordinate(3,9));blackCoordinateList.add(new Coordinate(2,5));blackCoordinateList.add(new Coordinate(6,9));blackCoordinateList.add(new Coordinate(7,1));}public static void main(String[] args) {for (int i = 0; i < blackCoordinateList.size() && i < whiteCoordinateList.size(); i++) {// 无论下了多少步,黑白棋子都只各创建了一个实例WhiteChess.getInstance().display(whiteCoordinateList.get(i));BlackChess.getInstance().display(blackCoordinateList.get(i));}
//        运行结果:
//        白棋落在{x=1, y=4}
//        黑棋落在{x=2, y=5}
//        白棋落在{x=2, y=3}
//        黑棋落在{x=6, y=9}
//        白棋落在{x=3, y=9}
//        黑棋落在{x=7, y=1}}}

1.1 单纯享元模式

在单纯享元模式中,所有的具体享元类都是可以共享的,不存在非共享具体享元类。

​​​​​​​1.2 复合享元模式

将一些单纯享元对象使用组合模式加以组合,形成复合享元对象。这样的复合对象本身不能共享,但是它们包括的单纯享元对象可以被共享。

图 复合享元模式结构图

复合享元模式可以确保复合享元类CompositeConcreteFlyweight中所包含的每个单纯享元类都具有相同的外部状态,而这些单纯享元的内部状态往往可以不同。

现实中,当男女双方结婚组合成一个家庭后,虽然双方在有些观念上有分歧,但是夫妻双方二人都会一起为这个家付出的。

public abstract class AbstractRole {public abstract String getRole();void forHome(String things) {System.out.println(getRole() + ":" + things );}}public class HusbandRole extends AbstractRole{@Overridepublic String getRole() {return "丈夫";}private HusbandRole() {}public static class ClassHolder {private final static HusbandRole instance = new HusbandRole();}public static HusbandRole getInstance() {return ClassHolder.instance;}}public class WifeRole extends AbstractRole{@Overridepublic String getRole() {return "妻子";}private WifeRole() {}private static class ClassHolder {private final static WifeRole instance = new WifeRole();}public static WifeRole getInstance() {return ClassHolder.instance;}}public class CompositeManAndWife extends AbstractRole{private final WifeRole wifeRole = WifeRole.getInstance();private final HusbandRole husbandRole = HusbandRole.getInstance();@Overridepublic String getRole() {return wifeRole.getRole() + "和" + husbandRole.getRole();}private CompositeManAndWife() {}private static class ClassHolder {private final static CompositeManAndWife instance = new CompositeManAndWife();}public static CompositeManAndWife getInstance() {return ClassHolder.instance;}}public class Client {public static void main(String[] args) {CompositeManAndWife.getInstance().forHome("赚奶粉钱");CompositeManAndWife.getInstance().forHome("孝敬父母");CompositeManAndWife.getInstance().forHome("去旅行");
//        运行结果:
//        妻子和丈夫:赚奶粉钱
//        妻子和丈夫:孝敬父母
//        妻子和丈夫:去旅行}
}

2 Java的String

public class StringTest {public static void main(String[] args) {String str1 = "hello 享元模式";String str2 = "hello 享元模式";String str3 = new String("hello 享元模式");String str4 = "hello " + "享元模式";String str5 = "hello ";str5 += "享元模式";System.out.println(str1 == str2); //trueSystem.out.println(str1 == str3); //falseSystem.out.println(str1 == str4); //trueSystem.out.println(str1 == str5); //false}}

JVM 开辟了一块存储区专门存储字符串常量,叫作字符串常量池(享元池),而不同的字符串则为不同的享元实体。当给String变量赋值字符串常量时,会在字符串常量池中创建这个字符串享元实体(如果不存在的话)。

而通过new String(“”)的方式创建时则另开辟一个内存空间,而不会直接从字符串常量池中取。最后一个判断为false,是因为str5 的初始字符串和比较的字符串不一致,然后str5通过”+”号连接字符串时,会创建新的字符串变量。

3 享元模式优缺点

优点:

  1. 客户极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份。
  2. 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同环境中被共享。

缺点:

  1. 需要分离出内部状态和外部状态,使系统变得复杂。
  2. 为了使对象可以共享,将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。

4 适用场景

  1. 系统中有大量相同或者相似的对象。
  2. 对象中大部分状态都可以外部化。
  3. 需要多次使用同一享元对象。

相关文章:

享元模式-提供统一实现对象的复用

下围棋时&#xff0c;分为黑白棋子。棋子都一样&#xff0c;这是出现的位置不同而已。如果将每个棋子都作为一个独立的对象存储在内存中&#xff0c;将导致内存空间消耗较大。我们可以将其中不变的部分抽取出来&#xff0c;只存储它的位置信息来实现节约内存。 图 围棋 1 享元模…...

Jenkins工具系列 —— 在Ubuntu 18.04上安装各种版本OpenJDK

文章目录 安装java方式一、使用apt-get工具安装方式二、手动安装java 卸载java各种版本OpenJDK安装包下载 安装java 方式一、使用apt-get工具安装 1、安装各种JAVA版本 若要安装新版本的java11&#xff0c;安装命令&#xff1a; sudo apt install default-jre若选择安装jav…...

vue基础-虚拟dom

vue基础-虚拟dom 1、真实dom目标2、虚拟dom目标 1、真实dom目标 在真实的document对象上&#xff0c;渲染到浏览器上显示的标签。 2、虚拟dom目标 本质是保存节点信息、属性和内容的一个JS对象 更新会监听变化的部分 给真实的DOM打补丁...

C#时间轴曲线图形编辑器开发2-核心功能实现

目录 三、关键帧编辑 1、新建Winform工程 &#xff08;1&#xff09;界面布局 &#xff08;2&#xff09;全局变量 2、关键帧添加和删除 &#xff08;1&#xff09;鼠标在曲线上识别 &#xff08;2&#xff09;键盘按键按下捕捉 &#xff08;3&#xff09;关键帧添加、删…...

【Git】初始化仓库配置与本地仓库提交流程

目录 一、仓库配置邮箱与用户名 二、本地仓库提交流程 一、仓库配置邮箱与用户名 【Git】Linux服务器Centos环境下安装Git与创建本地仓库_centos git仓库搭建_1373i的博客-CSDN博客https://blog.csdn.net/qq_61903414/article/details/131260033?spm1001.2014.3001.5501 在…...

学习day53

今天主要是做一个案例 TodoList 组件化编码流程&#xff1a; 1. 拆分静态组件&#xff1a;组件要按照功能点拆分&#xff0c;命名不要与html元素冲突 2.实现动态组件&#xff1a;考虑好数据的存放位置&#xff0c;数据是一个组件在用&#xff0c;还是一些组件在用&#xff1a…...

【最短路算法】SPFA

引入 在计算机科学的世界里&#xff0c;算法就像是星空中的繁星&#xff0c;各自闪烁着智慧的光芒。它们沉默而坚定&#xff0c;像是一群不语的哲人&#xff0c;默默地解答着世界的问题。 算法的步骤&#xff0c;如同优美的诗行&#xff0c;让复杂的问题在流转的字符中得以释…...

牛客网Verilog刷题——VL48

牛客网Verilog刷题——VL48 题目答案 题目 在data_en为高期间&#xff0c;data_in将保持不变&#xff0c;data_en为高至少保持3个B时钟周期。表明&#xff0c;当data_en为高时&#xff0c;可将数据进行同步。本题中data_in端数据变化频率很低&#xff0c;相邻两个数据间的变化&…...

Unity UGUI的Shadow(阴影)组件的介绍及使用

Unity UGUI的Shadow(阴影)组件的介绍及使用 1. 什么是Shadow(阴影)组件&#xff1f; Shadow(阴影)组件是Unity UGUI中的一个特效组件&#xff0c;用于在UI元素上添加阴影效果。通过调整阴影的颜色、偏移、模糊等属性&#xff0c;可以使UI元素看起来更加立体和有层次感。 2. …...

Kubernetes系列

文章目录 1 详解docker,踏入容器大门1.1 引言1.2 初始docker1.3 docker安装1.4 docker 卸载1.5 docker 核心概念和底层原理1.5.1 核心概念1.5.2 docker底层原理 1.6 细说docker镜像1.6.1 镜像的常用命令 1.7 docker 容器1.8 docker 容器数据卷1.8.1 直接命令添加1.8.2 Dockerfi…...

同步锁: synchronized

synchronized 1. synchronized的特性2. synchronized的使用3. synchronized的锁机制 1. synchronized的特性 原子性: 所谓原子性就是指一个操作或者多个操作&#xff0c;要么全部执行并且执行的过程不会被任何因素打断&#xff0c;要么就都不执行。可见性: 可见性是指多个线程…...

【微服务】springboot 多模块打包使用详解

目录 一、前言 1.1 为什么需要掌握多模块打包 二、工程模块概述 2.1 前后端不分离...

嵌入式工程师面试经常遇到的30个经典问题

很多同学说很害怕面试&#xff0c;看见面试官会露怯&#xff0c;怕自己的知识体系不完整&#xff0c;怕面试官考的问题回答不上了&#xff0c;所以今天为大家准备了嵌入式工程师面试经常遇到的30个经典问题&#xff0c;希望可以帮助大家提前准备&#xff0c;不再惧怕面试。 1&a…...

ER系列路由器多网段划分设置指南

ER系列路由器多网段划分设置指南 - TP-LINK 服务支持 TP-LINK ER系列路由器支持划分多网段&#xff0c;可以针对不同的LAN接口划分网段&#xff0c;即每一个或多个LAN接口对应一个网段&#xff1b;也可以通过一个LAN接口与支持划分802.1Q VLAN的交换机进行对接&#xff0c;实现…...

3 PostGIS基础查询

PostGIS 基础查询 数据库维护 ps aux | grep postgrespsql 使用命令登录数据库psql -U postgres -d testdb -h localhost -p 5432postgres用户名&#xff0c;testdb数据库名称&#xff0c;localhost ip地址&#xff0c;可以省略&#xff0c;5432端口&#xff0c;可以省略。 …...

Shell错误:/bin/bash^M: bad interpreter: No such file or directory

目录 错误原因和现象 解决方案 错误原因和现象 在执行shell脚本的时候&#xff0c;报错&#xff1a;/bin/bash^M: bad interpreter: No such file or directory。 是由于该脚本文件是在Windows平台编写&#xff0c;然后在MacOS平台中执行。 在Windows平台上文件是dos格式&…...

Golang之路---01 Golang的安装与配置

Golang之路—01 Golang语言安装与配置 官网上下载Windows环境下的安装包 官网下载地址 双击下载后的文件进行安装&#xff0c;可根据需要自定义选择解压后的文件位置。 接着新创建一个文件夹&#xff0c;保存Golang语言项目。 在里面新建bin,pkg,src三个文件夹。 环境变量…...

Anolis OS 8.8服务器采用docker容器方式搭建gerrit3.8.1服务

采用docker容器方式搭建gerrit3.8.1服务 一、选择管理帐户密码的方式二、部署gerrit服务1. 采用docker compose部署单服务的方式部分gerrit(1) docker-compose.yaml文件内容(2) 在docker-compose.yaml文件所在目录调用下面命令先进行初始化操作 2. 在宿主机上部署httpd服务用于…...

PyTorch 中的多 GPU 训练和梯度累积作为替代方案

动动发财的小手&#xff0c;点个赞吧&#xff01; 在本文[1]中&#xff0c;我们将首先了解数据并行&#xff08;DP&#xff09;和分布式数据并行&#xff08;DDP&#xff09;算法之间的差异&#xff0c;然后我们将解释什么是梯度累积&#xff08;GA&#xff09;&#xff0c;最后…...

Appium+python自动化(三十五)- 命令启动appium之 appium服务命令行参数(超详解)

简介 前边介绍的都是通过按钮点击启动按钮来启动appium服务&#xff0c;有的小伙伴或者童鞋们乍一听可能不信&#xff0c;或者会问如何通过命令行启动appium服务呢&#xff1f;且听一一道来。 一睹为快 其实相当的简单&#xff0c;不看不知道&#xff0c;一看吓一跳&#xf…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...