公用对象池

什么是对象池?

对象池顾名思义就是存放对象的池子,主要是为了重复利用对象。将不用的对象扔进池子里,需要用的时候再从池子中取出来。这样的一套机制我们称为对象池。

为什么用对象池?

其实从定义我们就可以看出来,说白了就是为了提高资源的复用性。减少频繁的创建和销毁。对程序而言,频繁的创建和销毁就意味着频繁地分配内存和释放内存,这种情况会引起内存抖动、内存碎片、增加GC的负担和触发频率等一些列的性能问题。

对象池的应用场景?

主要作用于频繁创建和销毁的对象,例如子弹

对象池实现

从定义来看,很显然每一种需要频繁创建和销毁的物体都需要实现一套自己对象池,因为在一个对象池中回收和取出的一定是相同的对象,那开发过程中我们可能会遇到很多种不同类型的对象,他们都需要重复利用,那么怎么能实现简单好用的对象池呢?有没有一种方法或模板可以实现所有类型对象的对象池呢?
有经验的开发到这里肯定会想到把对象池的对象给抽象,那么我们可以有一套抽象的对象池来管理抽象的对象,在使用的时候在把对象池和对象进行具象化。就像这样:

public abstract class IPool<T>{}

那下面是不是要想一下,这个抽象的对象池内部需要一些什么样的属性和方法?
首先我们肯定要给这个对象池定一个容量,还要有一个属性来表示当前的存储数量,我们肯定也要定义一个容器来存这些对象,根据对象池的特性我们可以用Queue或者Stack,那这里我选择了Queue。我们还需要一些抽象方法,来创建、回收、销毁对象,也许我们在从对象池中取对象时还需要一些初始化的操作,初始化时也许我们还要接收一些参数,那么这个操作也要抽象成方法。
那大致就是这样:

public abstract class IPool<T>{/// <summary>/// 对象池最大容量/// </summary>public int MaxCount = 20;/// <summary>/// 对象池当前存储数量/// </summary>public int Count => poolQueue == null ? 0 : poolQueue.Count;/// <summary>/// 回收队列/// </summary>private Queue<T> poolQueue = new Queue<T>();/// <summary>/// 创建对象/// </summary>/// <returns></returns>protected abstract T OnCreateItem();/// <summary>/// 获取对象之前(一般用来初始化对象数据)/// </summary>/// <param name="item">对象</param>/// <param name="userData">用户定义数据</param>protected abstract void OnGetBefore(T item, object userData);/// <summary>/// 回收对象时触发/// </summary>/// <param name="item">目标对象</param>/// <returns>是否可以回收</returns>protected abstract bool OnRecycle(T item);/// <summary>/// 销毁对象时触发/// </summary>/// <param name="item">目标对象</param>protected abstract void OnDestroyItem(T item);
}

上面我们基本上就把该抽象的方法都给抽象了,那我们也不能仅仅只是抽象吧好像什么实事也没做,那下面就要写一些看得见摸得着的实际的东西了。
最重要的我们需要取对象和回收对象,回收对象我们可能一次回收一个,也可能一次回收多个,可能这个回收的对象需要重复利用也可能直接舍弃销毁,我们还可能预加载一些对象为了在下一次使用时能快速的拿到
那完整的对象池如下方:

    /// <summary>/// 对象池/// </summary>/// <typeparam name="T">池对象泛型</typeparam>public abstract class IPool<T>{/// <summary>/// 对象池最大容量/// </summary>public int MaxCount = 20;/// <summary>/// 对象池当前存储数量/// </summary>public int Count => poolQueue == null ? 0 : poolQueue.Count;/// <summary>/// 回收队列/// </summary>private Queue<T> poolQueue = new Queue<T>();/// <summary>/// 预加载/// </summary>/// <param name="count">预加载数量</param>public void PreLoad(int count){count = Mathf.Min(count, MaxCount);if (Count >= count) return;T item;for (int i = Count; i < count; i++){item = OnCreateItem();Recycle(item);}}/// <summary>/// 取一个对象/// </summary>/// <param name="userData">用户定义数据</param>/// <returns></returns>public T Get(object userData=null){T t;if (Count == 0){t = OnCreateItem();}else{t = poolQueue.Dequeue();if (t == null) t = Get(userData);}OnGetBefore(t,userData);return t;}/// <summary>/// 回收对象/// </summary>/// <param name="item">目标对象</param>/// <param name="isDestroy">是否销毁</param>public void Recycle(T item,bool isDestroy=false){if (Count >= MaxCount) isDestroy = true;if (isDestroy){OnDestroyItem(item);}else{if (OnRecycle(item)){poolQueue.Enqueue(item);}else OnDestroyItem(item);}}/// <summary>/// 回收多个对象/// </summary>/// <param name="items">对象列表</param>/// <param name="isDestroy">是否彻底销毁</param>public void Recycles(IList<T> items,bool isDestroy=false){int count = items == null ? 0 : items.Count;if (count == 0) return;for (int i = 0; i < count; i++){Recycle(items[i],isDestroy);}}/// <summary>/// 创建对象/// </summary>/// <returns></returns>protected abstract T OnCreateItem();/// <summary>/// 获取对象之前(一般用来初始化对象数据)/// </summary>/// <param name="item">对象</param>/// <param name="userData">用户定义数据</param>protected abstract void OnGetBefore(T item, object userData);/// <summary>/// 回收对象时触发/// </summary>/// <param name="item">目标对象</param>/// <returns>是否可以回收</returns>protected abstract bool OnRecycle(T item);/// <summary>/// 销毁对象时触发/// </summary>/// <param name="item">目标对象</param>protected abstract void OnDestroyItem(T item);}

其实到这里就已经写完了,但考虑到有一些同学会问我怎么用???想着尽可能的让你们开箱即食,干脆,咬咬牙,跺跺脚,我再多写200字。
看好了,我要举栗子了…
就以GameObject的对象池为例吧,因为这个的使用频率还是挺高的。
那我们定义一个GameObjectPool来继承IPool,然后再把IPool里的抽象方法都给实现一遍。
喏!,就是这样了:

	public class GameObjectPool : IPool<GameObject>{protected GameObject prefab;public GameObjectPool(GameObject prefab){this.prefab = prefab;}protected override GameObject OnCreateItem(){if (prefab==null){Debug.LogError("GameObjectPool 创建对象失败,prefab不能为null");return null;}return GameObject.Instantiate(prefab);}protected override void OnGetBefore(GameObject item, object userData){item.SetActive(true);}protected override bool OnRecycle(GameObject item){item.SetActive(false);return true;}protected override void OnDestroyItem(GameObject item){GameObject.Destroy(item);}}

好了实现了,怎么样 简单吧。。。。
不是吧 ,都到这里了还要问怎么用。。。。
接着来:

public class Demo : MonoBehaviour
{/// <summary>/// cube预制体/// </summary>public GameObject cubePrefab;/// <summary>/// cube 对象池/// </summary>private GameObjectPool cubePool;//在使用的所有cube,方便一会我要回收它们private List<GameObject> cubes = new List<GameObject>();void Start(){//对象池初始化cubePool = new GameObjectPool(cubePrefab);//预加载5个CubecubePool.PreLoad(5);}private void Update(){//点击空格回收所有的cubeif (Input.GetKeyDown(KeyCode.Space)){cubePool.Recycles(cubes);cubes.Clear();}//点击C 创建一个Cubeif (Input.GetKeyDown(KeyCode.C)){GameObject cube = cubePool.Get();cube.transform.position =GetRandomPos();cubes.Add(cube);}}/// <summary>/// 得到一个随机位置/// </summary>/// <returns></returns>private Vector3 GetRandomPos(){return new Vector3(Random.Range(-10, 10), Random.Range(-10, 10), Random.Range(-10, 10));}}

基本上就是这样了,其它对象的对象池也像GameObjectPool的实现方式,继承IPool 实现所有的抽象方法就可以了。
好了 结束!
在这里插入图片描述

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

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

相关文章

算法金 | 我最常用的两个数据可视化软件,强烈推荐

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 抱个拳&#xff0c;送个礼 预警&#xff1a;今天文章的描述可能会让你有点别扭&#xff1b;如感到不适&#xff0c;请及时停止 在我行…

大数据面试题之数据库(1)

目录 数据库中的事务是什么&#xff0c;MySQL中是怎么实现的 MySQL事务的特性? 数据库事务的隔离级别?解决了什么问题?默认事务隔离级别? 脏读&#xff0c;幻读&#xff0c;不可重复读的定义 MySQL怎么实现可重复读? 数据库第三范式和第四范式区别? MySQL的…

MacOS 安装 mtr 网络检测工具

Install sudo brew install mtr sudo chown root $(which mtr) sudo chmod us $(which mtr) sudo chown root $(which mtr-packet) sudo chmod us $(which mtr-packet) Test mtr google.com

C# WPF 3D 数据孪生 系列六

数字孪生应用开发 应用开发中的布局需求 Grid基本使用 WPF 3D绘图 点云 系列五-CSDN博客 WPF UI 3D 多轴 机械臂 stl 模型UI交互-CSDN博客 WPF UI 3D 基本概念 点线三角面 相机对象 材质对象与贴图 3D地球 光源 变形处理 动作交互 辅助交互插件 系列三-CSDN博客 数字孪生 介…

015-GeoGebra基础篇-定点旋转物体、动态显示数值并显示运动轨迹

这可能是我能想到的最大概率可以被你搜索到的标题了&#xff0c;容我先喘口气~ 目录 一、成品展示二、涉及内容三、做图步骤&#xff08;1&#xff09;绘制三角形t&#xff08;2&#xff09;建立定点D&#xff08;3&#xff09;制作角度滑动条&#xff08;4&#xff09;图形绕点…

刷题Day42|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

198.打家劫舍 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;最简单的动态规划思路。递推公式是dp[j] Math.max(dp[j - 1], dp[j - 2] nums[j])&#xff0c;要么打劫第j个房子&#xff08;下一个打劫的房子不能和j相邻&#xff09;&#xff0c;要…

嵌入式Linux系统编程 — 6.7 实时信号

目录 1 什么是实时信号 2 sigqueue函数 3 sigpending()函数 1 什么是实时信号 等待信号集只是一个掩码&#xff0c;它并不追踪信号的发生次数。这意味着&#xff0c;如果相同的信号在被阻塞的状态下多次产生&#xff0c;它只会在信号集中被记录一次&#xff0c;并且在信号集…

CG-01D 室外露点变送器

产品概述 本系列产品是采用一款高度集成的温湿度式露点传感器芯片&#xff0c;芯片全量程标定的数字输出。 它采用CMOSens技术&#xff0c;确保产品具有较高的可靠性与优良的长期稳定性。传感器包括一个电容性聚合体湿度敏感元件和一个用能隙材料制成的温度敏感元件&#xff…

Windows 下用MSYS2 环境为RP2040 编译MicroPython 固件

就是想试试看MSYS2 能兼容到什么地步。自己做了个RP2040 板子&#xff0c;用了4MB 的Flash&#xff0c;默认的Micropython 固件是2MB 的&#xff0c;所以只能自己编译固件。 编译环境 MSYS2 的安装方法、基本配置什么的我就不管了&#xff0c;到处都有文章介绍这个。只提一点…

做一个自动校正英文拼写错误的程序 使用c++

概述一个自动校正英文拼写错误的程序的基本的方法&#xff0c;并提供一个简化的C实现。这个方法基于编辑距离&#xff08;Levenshtein距离&#xff09;和一个预定义的词典。 以下是实现这样一个程序的步骤&#xff1a; 创建一个词典&#xff08;单词列表&#xff09;计算编辑…

mac视频压缩简单办法,mac如何把视频压缩到指定大小内存

在数字时代&#xff0c;视频已成为我们日常生活和工作的重要交流工具。然而&#xff0c;视频文件体积庞大&#xff0c;给存储和分享带来了不少困扰。本文将为你揭秘视频压缩的秘密&#xff0c;让你轻松减小视频文件体积&#xff0c;提升分享效率&#xff01; 方法一下载文件压缩…

MySQL 8.4.1 LTS 容器镜像可以下载了

MySQL 8.4.1 LTS 版本和 9.0 是同一天上线的&#xff0c;都是7月1日&#xff0c;只是大家都聚焦在了 9.0 而没注意到 8.4.1&#xff0c;关于 9.0 的内容请戳这里&#xff1a; MySQL 9.0.0 新鲜出炉&#xff01;支持向量类型 MySQL 9.0 的VECTOR文档更新 MySQL 8.4.1 变更 MySQL…

Vue3实现过渡动画

认识动画 在开发中&#xff0c;我们想要给一个组件的显示和消失添加某种过渡动画&#xff0c;可以很好的增加用户体验&#xff1a; React框架本身并没有提供任何动画相关的API&#xff0c;所以在React中使用过渡动画我们需要使用一个第三方库 react-transition-group&#xf…

开发者工具攻略:前端测试的极简指南

前言 许多人存在一个常见的误区&#xff0c;认为测试只是测试工程师的工作。实际上&#xff0c;测试是整个开发团队的责任&#xff0c;每个人都应该参与到测试过程中。 在这篇博客我尽量通俗一点地讲讲我们前端开发过程中&#xff0c;该如何去测试 浏览器开发者工具简介 开…

【高中数学/极值问题】一条长为L的绳子,一面靠墙,另外三边组成矩形,问此矩形最大面积能是多少?

【问题】 一条长为L的绳子&#xff0c;一面靠墙&#xff0c;另外三边组成矩形&#xff0c;问此矩形最大面积能是多少&#xff1f; 【示意图】 【解析式】 设垂直于墙的两边长为x&#xff0c;则墙对边长为L-2x&#xff0c;围成的矩形面积Sx(L-2x) 写成标准的解析式为yx(L-2…

本地Windows电脑 连接 Windows 服务器

Windows电脑 连接 Windows 服务器 方式1&#xff1a;直接搜索 在电脑的搜索栏&#xff0c;输入“远程桌面连接” 可以选择点击 “打开” 或者直接按 回车键 “Enter”&#xff0c;打开 远程桌面连接 方式2&#xff1a;运行框打开服务器连接 同时按&#xff1a;Windows徽标键…

数字图像处理、机器视觉(计算机视觉)、计算图形学概念

数字图像处理&#xff08;Digital Image Processing&#xff09;--又称为计算机图像处理&#xff0c;它是指将图像信号转换成数字信号并利用计算机对其进行处理的过程&#xff0c;以提高图像的实用性&#xff0c;达到人们所要求的预期结果。从输入到输出来看&#xff0c;数字图…

java+springboot+Mysql“友书”综合书籍平台系统24489-计算机毕业设计项目选题推荐(附源码)

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;“友书”综合书籍平台当然也不能排除在外。“友书”综合书籍平台系统是以实际运用为开发背景&#xff0c;运用软件工程原…

搜维尔科技:详谈ART的工具追踪技术

您的生产流程中是否已经受益于刀具跟踪系统&#xff1f;您是否意识到它们的价值&#xff1f;因为它们可以优化您的装配顺序&#xff0c;从而节省您的时间和金钱。 目前我们提供两种工具跟踪解决方案&#xff1a; 1.ART与 VERPOSE的解决方案——易于使用的图像识别 安装在工…

‘prettier‘ 不是内部或外部命令,也不是可运行的程序

报错信息&#xff1a;‘prettier’ 不是内部或外部命令、操作系统或可运行的程序 表明系统无法识别prettier这一命令。 解释&#xff1a; 这通常发生在尝试在命令行中运行prettier这个代码格式化工具时&#xff0c;但系统未安装prettier或者prettier没有正确添加到系统的环境…