【设计模式-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.hqwc.cn/news/411795.html

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

相关文章

TCP 拥塞控制对数据延迟的影响

哈喽大家好&#xff0c;我是咸鱼 今天分享一篇文章&#xff0c;是关于 TCP 拥塞控制对数据延迟产生的影响的。作者在服务延迟变高之后进行抓包分析&#xff0c;结果发现时间花在了 TCP 本身的机制上面&#xff1a;客户端并不是将请求一股脑发送给服务端&#xff0c;而是只发送…

【5G Modem】5G modem架构介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

如何卸载旧版docker

环境&#xff1a; Docker1.13 centos7.6 问题描述&#xff1a; 如何卸载旧版docker 解决方案&#xff1a; 1.停止Docker服务。使用以下命令停止Docker服务&#xff1a; sudo service docker stop2.卸载Docker软件包。根据您的Linux发行版&#xff0c;使用适当的包管理器来…

k8s的对外服务---ingress

service的作用体现在两个方面&#xff1a; 集群内部&#xff1a;不断追踪pod的变化。他会更新endpoint中的pod对象&#xff0c;基于pod的IP地址不断变化的一种服务发现机制。 集群外部&#xff1a;类似负载均衡器&#xff0c;把流量IP端口&#xff0c;不涉及转发url(http、htt…

C++ 数论相关题目(约数)

1、试除法求约数 主要还是可以成对的求约数进行优化&#xff0c;不然会超时。 时间复杂度根号n #include <iostream> #include <vector> #include <algorithm>using namespace std;int n;vector<int> solve(int a) {vector<int> res;for(int i…

通过Vscode 简单创建一个vue3+element的项目

首先确保安装的nodejs是18版本以上 确保你安装了最新版本的 Node.js&#xff0c;并且你的当前工作目录正是打算创建项目的目录。在命令行中运行以下命令 VSCode打开终端 输入构建项目命令&#xff0c;个人推荐如果有cnpm使用cnpm npm create vuelatest cnpm create vuelate…

国科大-自然语言处理复习

自然语言处理复习 实体关系联合抽取流水线式端到端方法 检索式问答系统流水线方式信息检索&#xff08;IR&#xff09;阶段阅读理解&#xff08;RC&#xff09;阶段基于证据强度的重排基于证据覆盖的重排结合不同类型的聚合 端到端方式Retriever-Reader的联合学习基于预训练的R…

甜蜜而简洁——深入了解Pytest插件pytest-sugar

在日常的软件开发中,测试是确保代码质量的关键步骤之一。然而,对于测试报告的生成和测试结果的可读性,一直以来都是开发者关注的焦点。Pytest插件 pytest-sugar 以其清晰而美观的输出,为我们提供了一种愉悦的测试体验。本文将深入介绍 pytest-sugar 插件的基本用法和实际案…

【MySQL】权限控制

DCL-权限控制 查询权限 show grants for 用户名主机名;授予权限 grant 权限列表 on 数据库名.表名 to 用户名主机名;grant all on test.* to user%; %是通配符&#xff0c;表示任意主机。撤销权限 revoke 权限列表 on 数据库名.表名 from 用户名主机名;revoke all on test.*…

【Unity】【VRTK】【Pico】如何快速在VRTK中引入带动画的PICO控制器

【背景】 之前的VRTK篇章中,我只介绍了Oculus,Open VR,SImulator这三种Rig的配置方法,那么Pico如何融合VRTK进行开发呢? 【需要的开发包】 先像一个正常PICO项目那样导入PICO的SDK到Unity。VRTK 4的Package导入器中搜Pico,可以导入一个Pico的Integration,导入后Projec…

旅游平台day02

1. 用户注册 概述&#xff1a; 常见的注册方式&#xff1a;邮箱注册、手机号注册、昵称注册、或者以上几种同时支持 本项目仅仅支持手机号注册 需求&#xff1a; 项目启动后&#xff0c;访问regist.html进入注册页面 手机号校验 前后台都需要对手机号进行校验 前端校验&am…

SpringMVC(全局异常处理.动态接收Ajax请求)

1.全局异常处理 1 异常处理器 基于AOP 用户发起请求, SpringMVC接受请求, SpringMVC加载静态资源问题说明 请求过去了,但没有处理 规则说明:静态资源进入SpringMVC框架之后,没有找到要怎样处理静态资源的方法,所以他们就不解决,也就不显示 解决方法:SpringMVC基于Servlet处理…