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

    @Override
    public 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);
    }

    @Override
    public 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);
    }

    @Override
    public 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);
    }

    @Override
    public 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);
    }
}

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

在这里插入图片描述

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

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

总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第十五讲_css水平垂直居中的技巧

css水平垂直居中的技巧 1. 水平垂直居中&#xff08;场景一&#xff09;2. 水平垂直居中&#xff08;场景二&#xff09;3. 水平垂直居中&#xff08;场景三&#xff09;4. 水平垂直居中&#xff08;场景四&#xff09; 1. 水平垂直居中&#xff08;场景一&#xff09; 条件&a…

Python UI框架库之kivy使用详解

概要 Python是一种广泛使用的编程语言&#xff0c;而Kivy是一个用于创建跨平台移动应用和多点触控应用的开源Python框架。Kivy的设计目标是提供一种简单而强大的方式来构建富有创意的用户界面和交互体验。本文将详细介绍Kivy的基本概念、核心特性、布局系统、用户界面设计和实…

【服务器数据恢复】服务器迁移数据时lun数据丢失的数据恢复案例

服务器数据恢复环境&服务器故障&#xff1a; 一台安装Windows操作系统的服务器。工作人员在迁移该服务器中数据时突然无法读取数据&#xff0c;服务器管理界面出现报错。经过检查发现服务器中一个lun的数据丢失。 服务器数据恢复过程&#xff1a; 1、将故障服务器中所有磁盘…

macOS 13(本机)golang程序交叉编译成 ARM架构

## 背景 golang程序&#xff08;JuiceFS&#xff09;需要支持ARM64架构&#xff0c;重新编译&#xff1b; 本地环境&#xff1a;macOS&#xff1a;13 ## 操作 安装交叉编译工具&#xff1a; brew install FiloSottile/musl-cross/musl-cross --with-aarch64 可以在 /usr/l…

【MATLAB随笔】遗传算法优化的BP神经网络(随笔,不是很详细)

文章目录 一、算法思想1.1 BP神经网络1.2 遗传算法1.3 遗传算法优化的BP神经网络 二、代码解读2.1 数据预处理2.2 GABP2.3 部分函数说明 一、算法思想 1.1 BP神经网络 BP神经网络&#xff08;Backpropagation Neural Network&#xff0c;反向传播神经网络&#xff09;是一种监…

【Unity】【Pico】【VR开发】为何PICO打包后真机运行闪退

【背景】 设置步骤&#xff0c;项目配置都没问题&#xff0c;Build也成功&#xff0c;Unity版本是符合要求的2022LTS版本&#xff0c;但是一在真机上运行就闪退。 【分析】 由于并没有开版权验证&#xff0c;而且闪退后也并没有弹框说版权问题&#xff0c;所以还是怀疑环境有…

如何有效构建进攻性的网络安全防护策略

文章目录 前言一、进攻性安全策略的价值&#xff08;一&#xff09;进攻性安全和防御性安全的区别&#xff08;二&#xff09;进攻性安全带来一种新的测试和防御的方法&#xff08;三&#xff09;进攻性安全策略也比防御性安全策略更具前瞻性 二、进攻性安全策略的类型&#xf…

欠拟合与过拟合

欠拟合&#xff1a; 模型在训练集上表现不好&#xff0c;在测试集上也表现不好。模型过于简单 欠拟合在训练集和测试集上的误差都较大 通过代码展示欠拟合 import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression from skle…

【基于 InternLM 和 LangChain 搭建你的知识库】学习笔记

学习参考文档【基于 InternLM 和 LangChain 搭建你的知识库】 学习参考链接【书生・浦语大模型实战营第三课作业(基础进阶)】 理论 实战 收集原始数据 收集2018年-2020年几年间的优秀数学建模论文 修改脚本文件&#xff0c;测试文件 作业 复现课程知识库助手搭建过程 La…

直接在引导文件或引导U盘上洗白(适用于新装)

准备工作 方案适用于,在原机器上使用PE引导修改、U盘引导/SATA引导(引导盘可拆到其它机器上操作)、虚拟机制作镜像制作前期 所需软件 DiskGenius、读写镜像文件 ChipEasy_芯片无忧、ChipGenius 是读取u盘PID VID用的。 Notepad2(好用的编辑工具,可用来改PID和VID) …

基于 Level set 方法的医学图像分割

摘 要 医学图像分割是计算机辅助诊断系统设计中的关键技术。对于医学图像分割问题,它一般可分为两部分:(l)图像中特定目标区域(器官或组织)的识别;(2)目标区域完整性的描述与提取。相比于其他图像,医学图像的复杂性和多样性,使得传统的基于底层图像信息的分割方法很难取得好的…

win10系统postgresql重装软件后原数据如何迁移

1、备份postgresql安装目录下的data文件夹 2、重新安装postgresql同一版本的软件 3、停止postgresql-x64-12服务 4、替换data文件夹 删除postgresql安装后新的的data文件夹 删除后将第一步备份的data文件夹粘贴过来&#xff0c;还是同一位置 5、启动postgresql-x64-12服务 …

微信接入知识库定制化的AI会怎样?

想不想要一个更加了解你的chatgpt&#xff1f;或者想给chatgpt加入特定的知识库&#xff1f; LinkAI来帮你&#xff01; 通过LinkAI&#xff0c;无需openai的api key&#xff0c;直接使用chatgpt。无需考虑服务器代理配置&#xff0c;openai账号注册等&#xff01;自定义知识…

chromium+clangd快速代码跳转

在开发chromium的时候我们使用vscode工具进行开发&#xff0c;如果使用C插件发现很容就卡死计算机了。 所以我们使用clangd工具来查看chromium的代码。 一、安装 1.1 安装cland 在vscode中安装还是很简单的。 输入cland&#xff0c;点击安装即可 1.2 安装Download languag…

【MATLAB】逐次变分模态分解SVMD信号分解算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 逐次变分模态分解&#xff08;Sequential Variational Mode Decomposition&#xff0c;简称SVMD&#xff09;是一种用于信号处理和数据分析的方法。它可以将复杂的信号分解为一系列模态函数&#xff0c;每个…

在线项目实习|2024寒假项目实战火热报名中!

一、在线实习项目分类 二、在线实习项目流程 三、在线实习项目优惠及项目特色 1、师傅带练教学模式&#xff0c;手把手教你掌握 采用“师带徒”的教学模式&#xff0c;课程以“项目前置知识学习 师傅带练 项目实战”贯穿&#xff0c;强调动手实操&#xff0c;内容以代码落地为…

linux终端上传github提示:更新被拒绝,因为远程仓库包含您本地尚不存在的提交

问题&#xff1a; 提示&#xff1a;更新被拒绝&#xff0c;因为远程仓库包含您本地尚不存在的提交。这通常是因为另外 提示&#xff1a;一个仓库已向该引用进行了推送。再次推送前&#xff0c;您可能需要先整合远程变更 提示&#xff1a;&#xff08;如 git pull ...&#xff…

墙地砖外形检测的技术方案-图像形态学

基础理论 得到的灰度图像需进行二值化处理和区域填充&#xff0c;涉及两个步骤&#xff0c;第一&#xff0c;对图像进行分割&#xff0c;将图像分割成目标和背景&#xff1b; 第二&#xff0c;对分割后图像进行区域填充。本例中的背景为黑色&#xff0c;可以通过基本的全局阈…

simulink之state

状态 状态描述了无功系统的运行模式。在Stateflow图表中&#xff0c;状态用于顺序设计&#xff0c;以创建状态转换图。 状态可以是激活状态&#xff0c;也可以是非激活状态。一个状态的激活或不激活可以根据事件和条件而变化。事件的发生通过使状态变为激活或非激活来驱动状态…

尺寸公差分析DTAS3D-产品功能介绍-自主可控

DTAS 3D (Dimensional Tolerance Analysis System 3D)基于蒙特卡洛原理&#xff0c;按照产品的公差及装配关系进行建模&#xff0c;然后进行解析、仿真计算&#xff0c;最终预测产品设计是否能够满足其关键尺寸要求&#xff0c;同时预测产品合格率&#xff0c;并进行根源分析。…