公用对象池

news2024/12/23 3:33:39

什么是对象池?

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

为什么用对象池?

其实从定义我们就可以看出来,说白了就是为了提高资源的复用性。减少频繁的创建和销毁。对程序而言,频繁的创建和销毁就意味着频繁地分配内存和释放内存,这种情况会引起内存抖动、内存碎片、增加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个Cube
        cubePool.PreLoad(5);
    }
    
	private void Update()
	{
			//点击空格回收所有的cube
	        if (Input.GetKeyDown(KeyCode.Space))
	        {
	            cubePool.Recycles(cubes);
	            cubes.Clear();
	        }
			//点击C 创建一个Cube
	        if (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.coloradmin.cn/o/1893923.html

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

相关文章

基于矩阵分解算法的评分预测实现---信息检索课设以及所涉及的深度学习原理

一、实验环境 Windows,Python 3 Python作为主要编程语言,使用Python的Pandas、NumPy、Matplotlib等库 二、实验内容 主要任务 查阅相关资料,了解矩阵分解算法的基本概念、应用场景及其难点。重点了解SVD(Singular Value Decomposition,奇异值分解)系列方法。掌握Pyth…

2023年的Facebook营销:超级完整指南

Facebook营销不是可选的&#xff0c;是必须的。Facebook是世界上使用最多的社交平台&#xff0c;每天吸引22.9亿活跃用户。 它也不全是度假照片和虚张声势。对于53.2% 的 16-24 岁互联网用户&#xff0c;社交媒体是他们进行品牌研究的主要来源。而且&#xff0c;66% 的 Facebo…

红黑树插入删除流程(流程图)

红黑树插入删除流程&#xff08;流程图&#xff09; 红黑树性质 左根右(二叉树&#xff09;根叶黑&#xff08;根节点是黑色的&#xff09;不红红&#xff08;不存在相邻两个红色节点&#xff09;黑路同&#xff08;对于每个节点&#xff0c;从该节点出发到任一空叶节点所经过…

学会python——用python制作一个登录和注册窗口(python实例十八)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.登录和注册窗口 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读…

tapd 与国内外主流的8大项目管理软件大对比

对比Tapd与8大项目管理工具&#xff1a;PingCode、Worktile、Redmine、Teambition、广联达、Jira、禅道、飞书。 Tapd 是腾讯推出的一款敏捷开发管理工具&#xff0c;特别适合那些需要高效协作和快速迭代的敏捷开发团队。它支持多种敏捷方法论&#xff0c;包括Scrum和Kanban&am…

二轴机器人装箱机:重塑物流效率,精准灵活,引领未来装箱新潮流

在现代化物流领域&#xff0c;高效、精准与灵活性无疑是各大企业追求的核心目标。而在这个日益追求自动化的时代&#xff0c;二轴机器人装箱机凭借其较佳的性能和出色的表现&#xff0c;正逐渐成为装箱作业的得力助手&#xff0c;引领着未来装箱新潮流。 一、高效&#xff1a;重…

字节码编程ASM之生成变量并sout

写在前面 本文看下如何通过asm生成变量并sout。 1&#xff1a;代码 直接看代码吧&#xff0c;注释很详细&#xff0c;有不懂的&#xff0c;留言告诉我&#xff1a; package com.dahuyuo.asmtest;import org.objectweb.asm.*; import org.objectweb.asm.commons.AdviceAdapt…

PE文件学习

一、介绍 PE文件&#xff0c;即Portable Executable文件&#xff0c;是一种标准的文件格式&#xff0c;主要用于微软的Windows操作系统上。这种格式被用来创建可执行程序&#xff08;如.exe文件&#xff09;、动态链接库&#xff08;.DLL文件&#xff09;、设备驱动&#xff0…

千万不要用国产BI,不然你会发现它性价比奇高——以奥威BI软件为例

在信息技术日新月异的今天&#xff0c;企业对于商业智能&#xff08;BI&#xff09;软件的选择往往陷入了一个误区&#xff1a;盲目追求国际品牌&#xff0c;却忽视了身边那些性价比极高的国产精品。如果你不慎踏入了“千万不要用国产BI”的陷阱&#xff0c;那么奥威BI软件将是…

豆包Marscode体验官,体验云编程和AI助手加持的快乐

我正在参加「豆包MarsCode初体验」征文活动&#xff0c;活动链接&#xff1a;https://juejin.cn/post/7384997062416252939?utm_sourcejuejin&utm_mediumpush&utm_campaigntiyanguan Marscode官网地址&#xff1a;工作台 - MarsCode 其实早在前不久&#xff0c;我就…

谷歌地图 | 路线优化 API 助力企业解锁物流新潜能

在当今竞争激烈的市场环境中&#xff0c;企业面临着越来越大的压力&#xff0c;需要提高运营效率、降低成本并满足不断增长的客户期望。对于依赖车队进行交付或服务的企业来说&#xff0c;这些挑战尤为艰巨。 近日&#xff0c; Google 地图平台路线优化 API 已经正式上线。路线…

服务器工具集合推荐

推荐一个朋友开源的服务器运维整合工具,目前的功能包括: ddns&#xff0c;rdp、ssh终端、ftp、http代理&#xff0c;支持在线文件编辑&#xff0c;文件管理&#xff0c;docker&#xff0c;进程&#xff0c;系统监控、wol唤醒&#xff0c;电脑远程开机&#xff0c;点对点&#…

【STM32】在标准库中使用DMA

1.MDA简介 DMA全称Direct Memory Access,直接存储区访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作&#xff0c;传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输&#xff0c;也没有中断处理方式那样保留现场和…

科普文:Linux服务器性能调优之CPU调度策略和可调参数

概叙 进程 进程是操作系统虚拟出来的概念&#xff0c;用来组织计算机中的任务。计算机的核心是CPU&#xff0c;它承担了所有的计算任务&#xff1b;而操作系统是计算机的管理者&#xff0c;它负责任务的调度、资源的分配和管理&#xff0c;统领整个计算机硬件&#xff1b;应用…

Raylib 解决拖拽与绘制坐标,在GPU坐标与鼠标坐标不相同的解决办法

注意数字可以通过加减排列组合得出 原理&#xff0c;诞生于发现可以拖拽&#xff0c;数据加减&#xff0c;与左下角排列&#xff0c;发现坐标系可以按左下角为原点理解 int positionx 0 - draftx;int positiony 0 drafty; // 相对于左下角位置&#xff0c;水平方向就是当…

TensorRT-Int8量化详解

int8量化是利用int8乘法替换float32乘法实现性能加速的一种方法 对于常规模型有&#xff1a;y kx b&#xff0c;此时x、k、b都是float32, 对于kx的计算使用float32的乘法 对于int8模型有&#xff1a;y tofp32(toint8(k) * toint8(x)) b&#xff0c;其中int8 * int8结果为in…

软件安全测试之代码审计包括哪些内容?代码审计报告该如何获取?

在信息化时代&#xff0c;随着计算机技术的快速发展&#xff0c;软件产品已经成为了人们生活和工作中不可或缺的一部分。然而&#xff0c;随着软件产品的复杂性和应用范围的扩大&#xff0c;软件安全性问题日益凸显&#xff0c;给企业和个人带来了极大的风险。为了保障软件系统…

JAVA每日作业day7.4

ok了家人们今天学习了Date类和simpleDateformat类&#xff0c;话不多说我们一起看看吧 一.Date类 类 java.util.Date 表示特定的瞬间 ( 日期和时间 ) &#xff0c;精确到毫秒。 1.2 Date类的构造方法 public Date(): 用来创建当前系统时间对应的日期对象。 public Date(long …

BBA车主,千万别去试驾问界M9

文 | AUTO芯球 作者 | 雷慢&响铃 我劝你啊&#xff0c;千万别去试驾问界M9&#xff0c; 不然啊&#xff0c;可能1个小时50万就没了&#xff0c; 不信你看这个“大冤种”&#xff0c; 他曾经发誓打死不买电车&#xff0c; 考虑了三、四年换宝马X5&#xff0c; 结果谈完…