公用对象池

什么是对象池?

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

为什么用对象池?

其实从定义我们就可以看出来,说白了就是为了提高资源的复用性。减少频繁的创建和销毁。对程序而言,频繁的创建和销毁就意味着频繁地分配内存和释放内存,这种情况会引起内存抖动、内存碎片、增加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;请及时停止 在我行…

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;图形绕点…

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

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

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

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

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

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

Vue3实现过渡动画

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

【高中数学/极值问题】一条长为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徽标键…

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

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

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

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

UE5 05-利用 timeline 插值运动

理解成 unity Dotween DoMove 插值运动即可 AddTimeLine 节点 物体插值运动 物体插值缩放 一个timeline 可以K多个动画帧

基于STM32F103C8T6的同步电机驱动-CubeMX配置与IQmath调用

基于STM32F103C8T6的同步电机驱动-CubeMX配置与IQmath调用 一、功能描述: 上位机通过CAN总线实现对电机的运动控制,主要包含三种模式:位置模式、速度模式以及力矩模式。驱动器硬件核心为STM32F103C8T6,带相电压采集电路以及母线电压采集电路。其中供电电压12V。 PWM中心对…

DT浏览器很好用

DT浏览器是一款简单的浏览器&#xff0c;又是强大的浏览器&#xff0c;界面简洁大方&#xff0c;软件使用流畅。DT浏览器的网址收藏&#xff0c;人工智能写作&#xff0c;书法笔记等功能与众不同。DT浏览器的图文识别功能和笔记本搭配使用&#xff0c;可以对内容编辑修改和保存…

RestTemplate、MockMVC、Swagger

rest代码风格 硬编码的部分在实际开发中都是会替换成枚举对象 SpringMVC会自动把json格式的post请求转化为对应接收的 对象 响应请求时&#xff0c;也会自动把 对象转化为 json格式的 RestTemplate 浏览器的地址栏只能提供get请求访问后端&#xff0c;如果要使用post方式发送…

[A-03] ARMv8/ARMv9-多级Cache架构

ver 0.1 前言 前面文章我介绍了Cache的基本架构、Cache的详细的结构&#xff0c;有了一定的cache的基础&#xff0c;对cache机制也有了sense。实际上Cache作为CPU架构中存储机制的核心组件和CPU的微架构以及系统的总线架构还是密切相关的&#xff0c;不同的体系下&#xff0c…

传统数据处理系统存在的问题

传统应用的数据系统架构设计时&#xff0c;应用直接访问数据库系统。当用户访问量增加时&#xff0c;数据库无法支撑日益增长的用户请求的负载&#xff0c;从而导致数据库服务器无法及时响应用户请求&#xff0c;出现超时的错误。 出现这种情况以后&#xff0c;在系统架构上就采…

【Axure高保真原型】中继器表格——移入显示详情卡片案例

今天和大家分享中继器表格——移入显示详情卡片的原型模板&#xff0c;鼠标移入员工号或姓名会弹出员工卡片&#xff0c;可以查看更详细的信息。这个表格是用中继器制作的&#xff0c;所以使用也很方便&#xff0c;只需要维护中继器表格里的信息&#xff0c;即可自动生成交互效…

第一百四十二节 Java数据类型教程 - Java字符数据类型

Java数据类型教程 - Java字符数据类型 Character类的一个对象包装一个char值。 字符类包含isLetter()和isDigit()方法来检查字符是否为字母和数字。 toUpperCase()和toLowerCase()方法将字符转换为大写和小写。 该类提供了一个构造函数和一个工厂valueOf()方法来从char创建对…