【设计模式-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);}
}

可以发现,各个图块构造器内的输出语句只执行了一次,说明后续图块的创建没有调用其构造方法,实现了享元

在这里插入图片描述

以上就是通过享元模式对游戏地图设计的过程,实际上就是对最小单元对象的共享,使其不重复去创建对象。

需要注意区分于工厂设计模式,工厂模式是创建型设计模式,关注对象的创建,而享元模式是对已创建对象的一种利用,是结构型设计模式

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/626017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【二叉树遍历和练习】

文章目录 一、二叉树前中后遍历二、获取节点个数三.获取叶子节点个数四.获取第k层节点个数五.求二叉树的高度&#xff0c;时间复杂度O&#xff08;N&#xff09;六.检测值为value的元素是否存在七. 检查两颗树是否相同八.判断一棵二叉树是不是平衡二叉树九.一个二叉树的根节点 …

Hutool sqlserver 数据库简单操作-Db

项目中主数据库是mysql的&#xff0c;使用mybatis处理非常舒服。项目中还会极少量涉及一个sqlserver数据源的读取操作&#xff0c;虽然mybatis是支持多数据源的&#xff0c;但是感觉用起来不那么顺手偏重一些了。 最初我的想法是涉及sqlserver的库的操作直接使用jdbc来实现就好…

java基于Spring Boot的灾害应急救援评估调度平台

灾害应急救援平台的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。&#xff08;1&#xff09;鉴于该系统是一款面向…

深入理解和应用C++ std::shared_ptr别名构造函数

深入理解和应用C std::shared_ptr别名构造函数 引言 在现代C中&#xff0c;智能指针是一个极为重要的工具&#xff0c;尤其std::shared_ptr以其自动内存管理、引用计数和多线程安全性等特性深受开发者喜爱。其中一个不太常用但功能强大的构造方式是别名构造函数&#xff0c;它…

C++ 设计模式之外观模式

【声明】本题目来源于卡码网&#xff08;题目页面 (kamacoder.com)&#xff09; 【提示&#xff1a;如果不想看文字介绍&#xff0c;可以直接跳转到C编码部分】 【简介】什么是外观模式 外观模式Facade Pattern , 也被称为“⻔⾯模式”&#xff0c;是⼀种结构型设计模式&#…

WordPress如何修改旧文章的发布日期让其变成新文章发布?

我们个人网站发展一段时间后&#xff0c;可能就不懂得发布什么内容了&#xff0c;这个时候可以考虑翻看以前的旧文章&#xff0c;必要时对其进行适当修改&#xff0c;然后修改它的发布日期变成当前日期重新发布&#xff0c;这样就会变成新文章重新出现在我们首页的文章列表中。…

libbpf-tips

使用 libbpf 编写 BPF 应用程序进阶技巧 本文地址&#xff1a;https://www.ebpf.top/post/top_and_tricks_for_bpf_libbpf 原文地址&#xff1a;https://www.pingcap.com/blog/tips-and-tricks-for-writing-linux-bpf-applications-with-libbpf/ 2020 年初&#xff0c;当使用…

numpy 筛选多段数据

目录 掩码方式 利用切片 掩码方式 range_to_remove list(range(77-1, 111-1)) list(range(122-1, 135-1))keep_mask np.ones(image0_cut.shape[0], dtypebool)keep_mask[range_to_remove] Falseprocessed_data image0_cut[keep_mask] 利用切片 import numpy as np# 假设…

基于Pytorch的身份证及其他证件检测矫正模型应用

前言 在做身份证和其他证件识别的时候&#xff0c;图片基本都不是摆正的状态&#xff0c;此时在进行OCR文字识别的提取文字信息的时候会出现很多误差&#xff0c;如何将证件摆正&#xff0c;再进行OCR文字识别就可以大大提高准确率。 准备工作 1、Python环境&#xff0c;在P…

tda7294功放电路图大全

简易电子管功放电路图&#xff08;一&#xff09; 6P3P单端A类电子管功放电路图 如图为6P3P单端A类电子管功放电路图。VT1、VT2直流通路串联。VT1构成普通的三极管共阴放大器&#xff0c;VTr2构成阴极输出器&#xff0c;对VT1而言VT2是一个带电流负反馈的高阻负载。音频信号由…

Leetcode2696. 删除子串后的字符串最小长度

Every day a Leetcode 题目来源&#xff1a;2696. 删除子串后的字符串最小长度 解法1&#xff1a;暴力 暴力做法是不断把 AB 和 CD 去掉&#xff0c;直到 s 中没有 AB 和 CD 为止。 代码&#xff1a; /** lc appleetcode.cn id2696 langcpp** [2696] 删除子串后的字符串最…

漏洞复现-金和OA jc6/servlet/Upload接口任意文件上传漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

关于浮点数的四舍五入问题

最近有关注到&#xff0c;在C/C中&#xff0c;对于浮点数的四舍五入&#xff0c;与实际的有一些出入&#xff0c;我打算今天总结一下&#xff0c;并解释一下这是为啥&#xff0c; 好了&#xff0c;下面进入正题&#xff0c;都是干货哦&#xff0c;认真看完&#xff0c;留下你的…

【大模型应用】小白借助chatgpt开发谷歌插件

大模型正缓慢地渗透进入我们的生活&#xff0c;尽管目前还没有现象级的产品应用&#xff0c;但它已足以让我痴迷于它&#xff0c;我对它能够提升程序员的生产效率笃定无疑。 本次我用一个下午做了一次尝试&#xff0c;使用大模型帮助我开发一个谷歌插件。开发之前&#xff0c;…

西米支付:到底什么是NFT(数字藏品支付通道)(NFT支付通道)

NFT到底指的是什么呢&#xff1f; 数字藏品的实际意义在于它们打破了传统艺术品的物质形态束缚。数字藏品可以通过虚拟现实和区块链技术进行创作、展示和交易。它们不仅可以满足人们对艺术品的审美需求&#xff0c;还可以成为一种投资和资产保值增值的方式。数字藏品的实际意义…

排序——归并排序

文章目录 基本思想递归版本思路代码实现 非递归版思路代码实现 特性结果演示 基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子…

开发实践6_缓存^中间件

以下学习 朔宁夫 开发工程师 课程。 缓存可提高程序响应速度。数据库缓存(可过期)/ Redis缓存(Key:Value)/ Memcacheed缓存/ 程序层缓存。 一 缓存 1. 数据库缓存 创建缓存数据表 // python manage.py createcachetable cache_table setting // # 缓存配置 CACHES {def…

第十部分 make 的运行

目录 一、make 的退出码 二、指定 Makefile 三、指定目标 “all” “clean” “install” “print” “dist” “TAGS” “check”和“test” 四、检查规则 五、make 的参数 一般来说&#xff0c;最简单的就是直接在命令行下输入 make 命令&#xff0c;make 命令会…

代码随想录算法训练营第20天(二叉树6 | 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

二叉树 part06 654.最大二叉树解题思路 617.合并二叉树解题思路 700.二叉搜索树中的搜索解题思路 98.验证二叉搜索树解题思路误区 654.最大二叉树 又是构造二叉树&#xff0c;昨天大家刚刚做完 中序后序确定二叉树&#xff0c;今天做这个 应该会容易一些&#xff0c; 先看视频&…

12.云原生之kubesphere中应用部署方式

云原生专栏大纲 文章目录 k8s中应用部署Kubernetes常用命令 kubesphere中可视化部署应用创建工作负载服务暴露 helm部署应用helm命令行部署应用kubesphere中使用应用仓库 k8s中应用部署 在k8s中要想部署应用&#xff0c;需要编写各种yaml文件&#xff0c;一旦应用依赖比较复杂…