一种对象池实现方案

狂风中的少年 提交于 2020-01-11 02:40:09

对象池能让创建对象的cpu开销减少,也可以让内存控制再一定的数量上,是大量角色或物体创建移除的比较合适的解决方案。但很多用的是针对指定类型或场景下使用的对象池,很难做到通用。最近研究到,有这样一套对象池的解决方案。

这套解决方案同样会分为获取Get,移除Release后回收。只是可以自定义我们需要获得的对象类型。

代码如下:

//Game 中对象池ObjectPool
//需要自定义TypeOp.ObjCreator来创建对象
//需要自定义TypeOp.ObjClear来清理对象
//#define OBJECT_POOL_DEBUG
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace QMGame
{
    public static class ObjectPool
    {
        private static Dictionary<Type, object> poolDictionary = new Dictionary<Type, object>();

        const int TotalNum = 30;

        public static void Clear()
        {
            poolDictionary.Clear();
        }

        /// <summary>
        /// 如果对象池中有则返回对象池中的,不然就Activator.CreateInstance
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Get<T>()
        {
            Type t = typeof(T);
            object pooledObjects;
            //1.先查看对象池中是否存在可用的指定类型对象
            if (poolDictionary.TryGetValue(t, out pooledObjects))
            {
                List<object> lstObjects = pooledObjects as List<object>;
                if (lstObjects.Count > 0)
                {
                    //获取可用对象,并且再对象池中移除掉
                    object obj = lstObjects[lstObjects.Count - 1];
                    lstObjects.RemoveAt(lstObjects.Count - 1);
                    return (T)obj;
                }
            }

            //没找到则需要去创建新对象
            return (T)NewObject(t);
        }

        private static object NewObject(Type t)
        {
            PoolObject po = null;
            //2.我们指定的类型中是否包括了我们指定的类型
            if (ObjectPoolHelper.objectCreator.TryGetValue(t, out po))
            {
                //有则创建,创建的方法再ObjectPoolHelper的creator中执行
                if (po.creator != null)
                    return po.creator();
            }
            
            //3.实在连指定类型中都没有,说明项目中没有指定该类型为需要用对象池的类型,则直接创建。
            return Activator.CreateInstance(t);
        }

        /// <summary>
        /// 外部执行可以释放一个对象到对象池了
        /// </summary>
        /// <param name="obj"></param>
        public static void Return(object obj)
        {
            if (obj == null) { return; }

            object pooledObjects;
            Type t = obj.GetType();
            PoolObject po = null;
            //对象池指定类型如果包括这个类型则需要在对象池中释放
            if (ObjectPoolHelper.objectCreator.TryGetValue(t, out po))
            {
                //执行移除的方法,具体执行也是在我们指定的类型中
                if (po.clear != null)
                {
                    po.clear(obj);
                }
            }
            else 
            {
                //LogWarning("未配置对象操作委托,请按照规范使用ObjectgPool");

                return;
            }

            //该类型的对象池中是否包含他
            if (poolDictionary.TryGetValue(t, out pooledObjects))
            {
                List<object> lstObjects = pooledObjects as List<object>;
#if UNITY_EDITOR && OBJECT_POOL_DEBUG
            for (int i = 0; i < lstObjects.Count; i++)
            {
                if (lstObjects[i] == obj)
                {
                    LogWarning("此对象被重复添加到对象池: {0},请检查ObjectPool的使用是否符合规范!", t.ToString());
                    return;
                }
            }
#endif
                //没有到上限则加上,超过上限则不加入了。对象已经通过clear移除了,这里只是看需不需要加回到对象池中,既然都超过了上限了,就不需要他加入了
                if (lstObjects.Count < TotalNum)
                    lstObjects.Add(obj);
                else
                {
                    DebugHelper.LogWarning("对象池中缓存的对象{0}数量超过阈值,请检查对象的创建流程是否使用了对象池", t.ToString());
                }
            }
            else
            {
                //对象池中不包含这个对象则加入
                List<object> lstObjects = new List<object>();
                poolDictionary.Add(t, lstObjects);

                lstObjects.Add(obj);
            }
        }
    }

}

上面是获取对象和移除对象的相关方法,在正式使用中需要成对使用,才能正常获取和释放。

using System.Collections.Generic;
using UnityEngine;
using System;
using BumperCar;

namespace QMGame
{
    public delegate object ObjectCreator();
    public delegate void ObjectClear(object obj);

    public class PoolObject
    {
        public ObjectCreator creator;
        public ObjectClear clear;
    }

    public class ObjectPoolHelper
    {
        public static Dictionary<Type, PoolObject> objectCreator = new Dictionary<Type, PoolObject>()
        {
            {
                //指定List<Actor>类型,然后给他两个方法,一个是创建,我们指定如何创建他。一个移除方法,指定如何移除。这里需要我们手动指定
                typeof(List<Actor>),
                new PoolObject()
                {
                    creator = delegate {return new List<Actor>(); },
                    clear = obj =>{
                        List<Actor> list = obj as List<Actor>;
                        list.Clear();
                    }
                }
            },
            {
                //指定ChangeForwardCommandData类型,然后给他两个方法,一个是创建,我们指定如何创建他。一个移除方法,指定如何移除。这里需要我们手动指定
                typeof(ChangeForwardCommandData),
                new PoolObject()
                {
                    creator = () => { return new ChangeForwardCommandData(); },
                    clear = (obj) => {
                        ChangeForwardCommandData data = obj as ChangeForwardCommandData;
                        data.Clear();
                    }
                }
            }
            
        };
    }
}

上面是指定的类型的对象池。需要手动设定。

 

使用示例:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!