【设计模式-3.3】结构型——享元模式
说明:说明:本文介绍设计模式中结构型设计模式中的,享元模式;
游戏地图
在一些闯关类的游戏,如超级玛丽、坦克大战里面,游戏的背景每一个关卡都不相同,但仔细观察可以发现,其都是用一些基础图标组成的,背景的变化实际上就是改变了其基础图标的位置。
如坦克大战,游戏背景实际上就是通过敌方坦克、我方坦克、砖墙、铁墙、海洋、草丛、基地等这些图标组成的。

基础图标,坦克、草地、河流……



现在,如果要我们来开发这样一个游戏地图。首先,我们会创建一个地图块类,如下:
(Tile,图块类)
/*** 图块类*/
public class Tile {/*** 图块名称*/private String image;/*** 图块的x坐标*/private int x;/*** 图块的y坐标*/private int y;/*** 创建图块对象*/public Tile(String image, int x, int y) {this.image = image;this.x = x;this.y = y;System.out.println("加载图片:" + image);}/*** 绘制图块*/public void draw() {System.out.println("绘制图片:" + image + ",坐标:" + x + "," + y);}
}
(Client,客户端,演示游戏地图创建过程)
/*** 客户端*/
public class Client {public static void main(String[] args) {// 在地图上绘制两个“海洋”图块new Tile("海洋", 1, 2).draw();new Tile("海洋", 2, 3).draw();// 在地图上绘制两个“草丛”图块new Tile("草丛", 1, 3).draw();new Tile("草丛", 2, 4).draw();// 在地图上绘制两“砖墙”图块new Tile("砖墙", 1, 4).draw();new Tile("砖墙", 2, 5).draw();}
}
运行程序,加载游戏地图

分析以上过程,会发现问题很大。每次创建一个图块对象,都需要new,加载时间特别长,且浪费资源。
为了解决这个问题,我们似乎可以考虑用原型设计模式解决。但是我们需要考虑,对于一个游戏地图来说,图块种类的数量可能是非常庞大的,使用原型模式对对象进行克隆,会有大量的内存开销,如果没有良好的内存回收机制,可能会导致内存溢出,造成系统崩溃。因此,使用原型模式来解决游戏地图的设计,不一定是合适的。
享元模式
享元,元指的是最小的单元,也就是上面坦克大战中草丛、海洋这些最小的图块,享元就是共享这些最小图块。通过享元模式对上面地图加载代码改进,如下:
(Drawable,绘画接口)
/*** 绘画接口*/
public interface Drawable {/*** 绘制图块*/void draw(int x, int y);
}
(Grass,草地图块)
/*** 草地图块*/
public class Grass implements Drawable {/*** 图块名称*/private String name;public Grass() {this.name = "草地";System.out.println("创建图块:" + name);}@Overridepublic void draw(int x, int y) {System.out.println("绘制【" + name + "】图块:" + name + ",位置:(" + x + ", " + y + ")");}
}
(Wall,墙壁图块)
/*** 墙壁图块*/
public class Wall implements Drawable {/*** 图块名称*/private String name;public Wall() {this.name = "墙壁";System.out.println("创建墙壁图块:" + name);}@Overridepublic void draw(int x, int y) {System.out.println("绘制【" + name + "】图块:" + name + ",位置:(" + x + ", " + y + ")");}
}
(River,河流图块)
/*** 河流图块*/
public class River implements Drawable {/*** 图块名称*/private String name;public River() {this.name = "河流";System.out.println("创建图块:" + name);}@Overridepublic void draw(int x, int y) {System.out.println("绘制【" + name + "】图块:" + name + ",位置:(" + x + ", " + y + ")");}
}
(Home,基地图块)
/*** 基地图块*/
public class Home implements Drawable {/*** 基地图块名称*/private String name;public Home() {this.name = "基地";System.out.println("创建图块:" + name);}@Overridepublic void draw(int x, int y) {System.out.println("绘制【" + name + "】图块:" + name + ",位置:(" + x + ", " + y + ")");}
}
(TileFactory,图块工厂)
import java.util.HashMap;
import java.util.Map;/*** 图块工厂*/
public class TileFactory {/*** 图块集合*/private Map<String, Drawable> Tiles;/*** 图块工厂构造函数*/public TileFactory() {Tiles = new HashMap<String, Drawable>();}/*** 根据图块名称获取图块,没有就创建并返回,有就直接从集合中获取并返回*/public Drawable getTile(String name) {// 没有就创建if (!Tiles.containsKey(name)) {switch (name) {case "河流":Tiles.put(name, new Wall());break;case "草地":Tiles.put(name, new Grass());break;case "基地":Tiles.put(name, new Home());break;case "墙壁":Tiles.put(name, new Wall());break;default:break;}}// 有就直接返回return Tiles.get(name);}
}
(Client,客户端,演示游戏地图加载过程)
/*** 客户端*/
public class Client {public static void main(String[] args) {// 创建图块工厂TileFactory tileFactory = new TileFactory();// 绘制地图tileFactory.getTile("草地").draw(0, 0);tileFactory.getTile("草地").draw(1, 0);tileFactory.getTile("草地").draw(2, 0);tileFactory.getTile("河流").draw(0, 1);tileFactory.getTile("河流").draw(1, 1);tileFactory.getTile("墙壁").draw(0, 2);tileFactory.getTile("墙壁").draw(1, 2);tileFactory.getTile("基地").draw(0, 3);}
}
可以发现,各个图块构造器内的输出语句只执行了一次,说明后续图块的创建没有调用其构造方法,实现了享元

以上就是通过享元模式对游戏地图设计的过程,实际上就是对最小单元对象的共享,使其不重复去创建对象。
需要注意区分于工厂设计模式,工厂模式是创建型设计模式,关注对象的创建,而享元模式是对已创建对象的一种利用,是结构型设计模式。
总结
本文参考《设计模式的艺术》、《秒懂设计模式》两书
相关文章:
【设计模式-3.3】结构型——享元模式
说明:说明:本文介绍设计模式中结构型设计模式中的,享元模式; 游戏地图 在一些闯关类的游戏,如超级玛丽、坦克大战里面,游戏的背景每一个关卡都不相同,但仔细观察可以发现,其都是用…...
【征服redis6】Redis的内存淘汰详解
目录 1.redis的基本策略 2.Redis中的缓存淘汰策略 3.Redis内存不足的情况 4.几种淘汰策略的实现原理 5.项目实践与优化策略 5.1 配置案例 5.2 项目优化策略参考 数据库存储会将数据保存到磁盘中,而Redis的核心数据是在内存中的,而Redis本身主要用来…...
多文件转二维码的两种方式,有兴趣的了解一下
多个文件能一键生成二维码吗?二维码是现在很多人用来展示文件内容的一种手段,在制作二维码图片之后,其他人扫码就可以查看文件或者下载文件,有效的提升文件获取的效率。一般情况下,文件二维码分为多个文件生成一个二维…...
uniapp APP接入Paypal
1. 登录paypal开发者中心, 2. 选择 Apps & Credentials 点击 Create App创建应用,创建后点击编辑按钮,如图: 3. 进入应用详情,勾选Log in with PayPal点击 Advanced Settings 添加return URL等信息并保存。如图&a…...
QT-贪吃小游戏
QT-贪吃小游戏 一、演示效果二、关键程序三、下载链接 一、演示效果 二、关键程序 #include "Snake.h" #include "Food.h" #include "Stone.h" #include "Mushroom.h" #include "Ai.h" #include "Game.h" #inclu…...
HubSpot:如何设计和执行客户旅程?
在当今数字化时代,企业成功的关键之一是建立并优化客户旅程。HubSpot作为一体化市场营销平台,通过巧妙设计和执行客户旅程,实现了个性化决策,关键节点的精准引导,为企业带来了数字化转型的引领力。 一、HubSpot是如何设…...
【Go学习】macOS+IDEA运行golang项目,报command-line-arguments,undefined
写在前面的话:idea如何配置golang,自行百度 问题1:通过idea的terminal执行go test报错 ✘ xxxxxmacdeMacBook-Pro-3 /Volumes/mac/.../LearnGoWithTests/hello go test go: go.mod file not found in current directory or any parent …...
优先看我的博客:工控机 Ubuntu系统 输入密码登录界面后界面模糊卡死,键盘鼠标失效(不同于其他博主的问题解决方案,优先看我的博客。)
工控机Ubuntu 输入密码登录界面后界面模糊卡死,键盘鼠标失效 (不同于其他博主的问题解决方案,工控机Ubuntu的系统 优先看我的博客。) 系统版本:ubuntu18.04 主机:工控机 应用场景:电力系统巡…...
SAP 中的外部接口:预扣税
文章目录 1 Introduction2 implementation3 Summary 1 Introduction We use BP create WTAX_TYPE ,I don’t find a bapi. We will update for it . We will impement WTax type , WTax code ,Subject in the ‘BP’. 2 implementation UPDATE lfbw SET witht gs_alv-wit…...
代码随想录算法训练营第二十三天| 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树
669. 修剪二叉搜索树 题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 解题思路:如果当前结点小于所给区间,那该节点及其左子树肯定不符合条件,返回其右子树作为上一结点子树;反之…...
设计模式——解释器模式
解释器模式(Interpreter Pattern)是一种行为型设计模式,它提供了一个框架,用于定义语言的语法规则,并通过这些规则来解析和解释特定语法结构表示的句子。这种模式主要应用于需要对简单语言进行解释或编译的小型系统中。…...
uniapp小程序当页面内容超出时显示滚动条,不超出时不显示---样式自定义
使用scroll-view中的show-scrollbar属性 注意:需要搭配enhanced使用 否则无效 <scroll-view class"contentshow" scroll-y :show-scrollbartrue :enhancedtrue><view class"content" :show-scrollbartrue><text>{{vehicleCartinfo}}<…...
开源28181协议视频平台搭建流程
最近项目中用到流媒体平台,java平台负责信令部分,c平台负责流媒体处理,找了评分比较好的开源项目 https://gitee.com/pan648540858/wvp-GB28181-pro 流媒体服务基于 c写的 https://github.com/ZLMediaKit/ZLMediaKit 说明文档:h…...
安全跟我学|网络安全五大误区,你了解吗?
网络安全 尽管安全问题老生常谈,但一些普遍存在的误区仍然可能让企业随时陷入危险境地。为了有效应对当前层出不穷且不断变换的网络威胁,最大程度规避潜在风险,深入了解网络安全的发展趋势必不可少。即使部署了最新且最先进的硬件和解决方案…...
数据结构奇妙旅程之二叉树初阶
꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …...
WebGL中开发VR(虚拟现实)应用
WebGL(Web Graphics Library)是一种用于在浏览器中渲染交互式3D和2D图形的JavaScript API。要在WebGL中开发VR(虚拟现实)应用程序,您可以遵循以下一般步骤,希望对大家有所帮助。北京木奇移动技术有限公司&a…...
elemeentui el-table封装
elemeentui el-table封装 <template><div style"height: 100%;"><el-table ref"sneTable" element-loading-text"加载中" element-loading-spinner"el-icon-loading"element-loading-background"rgba(45,47,79…...
openssl3.2 - 官方demo学习 - guide - quic-client-block.c
文章目录 openssl3.2 - 官方demo学习 - guide - quic-client-block.c概述笔记END openssl3.2 - 官方demo学习 - guide - quic-client-block.c 概述 在程序运行时, 要指定环境变量 SSL_CERT_FILErootcert.pem, 同时将rootcert.pem拷贝到工程目录下, 否则不好使 吐槽啊, 为啥不…...
滑动窗口经典入门题-——长度最小子数组
文章目录 算法原理题目解析暴力枚举法的代码优化第一步初始化第二步right右移第三步left右移 滑动窗口法的代码 算法原理 滑动窗口是一种在序列(例如数组或链表)上解决问题的算法模式。它通常用于解决子数组或子字符串的问题,其中滑动窗口表示…...
AcGeMatrix2d::alignCoordSys一种实现方式
问题描述 此处为了简化问题,在2维空间中处理,按以下方式调用,AcGeMatrix2d::alignCoordSys是如何求出一个矩阵的呢,这里提供一个实现思路(但效率不保证好) AcGeMatrix2d matTrans AcGeMatrix2d::alignCo…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
