GameFramework解读一:对象池

1.前言【只会写出关键代码,其他代码都是可以自己扩展的,代码中对于get,set函数不会写】

嗨,大家好,我是言出必行的小白鸟。
在这个系列中我会将GameFramework中的所有模块边学习边将自己思考的东西写下来,希望可以帮助到有需要的同学~
对了,在这个系列中暂时不会使用Gameframework来做任何东西,只是将Gameframework中的模块进行解读,学习其中的思想。
【最近要实习了,虽然想做到日更,嗯。。。尽力吧!】

对象池的流程图

测试模块 ReferencePool ReferenceCollection IReference 访问对象池,获取对象 访问字典中的收集器,获取对象 获取字典中的对象,并返回 获取到了对象并返回 获取到了对象并返回 测试模块 ReferencePool ReferenceCollection IReference

2.IReference

在框架中所有的对象都要继承该接口。
问:Why?

答:所有的对象都会受到对象池的管理,对象那么多,所以我们应该定一个抽象类或接口来抽象它。

问:为什么定义的是接口而不是抽象类呢?

答:因为每个对象在对象池中都是可以被复用的,所以对象应该具有一个可以重置自己的Clear方法,但是在抽象类中我们并没办法去处理,那么使用接口就很合适,当然了,使用抽象类的虚方法再覆写也没有问题。

下面展示一些 内联代码片

public interface IReference
    {
        /// <summary>
        /// 清理引用。
        /// </summary>
        void Clear();
    }

3.ReferencePool.ReferenceCollection

【在这需要注意ReferenceCollection是ReferencePool中的内部类】
问:在这个ReferencePool类中为什么会有partial关键字?

答:这是为了逻辑的清晰【一个类看上去代码少,这样别人看了才不会后害怕吧】,将一个类分成了多个部分,其中在ReferencePool中只负责对ReferenceCollection的编码,而在ReferenceCollection中才是负责对实际对象的编码。

问:这也太方便了吧!那我在ReferencePool中就只关注

ReferenceCollection,在ReferenceConllection中只关注对象就可以了!
答:是啊!

问:咦,这里还有一个关键字sealed,这是啥呀?

答:对于不需要继承的类,我们就可以使用这个sealed密封关键字来标记,你可以把它当作是一个完整的产品,不需要再进行封装了

public static partial class ReferencePool
{
	//我知道,在这里我只需要关注如何去操作对象就可以了!其他什么乱七八糟的不去理他
    public sealed class ReferenceCollection
    {
    	//用来保存对象引用的队列
        private readonly Queue<IReference> m_References;
        //一个对象收集器负责一种类型的对象
        private readonly Type m_ReferenceType;
        
        public ReferenceCollection(Type referenceType)
        {
            m_References = new Queue<IReference>();
        }
        //让我们先来实现怎么添加引用到对象池吧!
        //因为是在编写底层,那么我们就不要去使用具体的类,用泛型T来表示
        public void Add<T>(int count) where T : class, IReference, new()
        {
        	//一个对象收集器只能负责一种类型的对象,如果类型和收集器类型不匹配就报错
            if (typeof(T) != m_ReferenceType)
            {
                throw new GameException("类型不匹配");
            }
            //锁住容器,虽然在Unity客户端中应该不会有多线程会访问,但在服务器的话就需要上锁以免被多个线程访问,造成异常
            lock (m_References)
            {
                while (count-- > 0)
                {
//利用Type来实例化出来对于的对象并放入队列
                    m_References.Enqueue((IReference)Activator.CreateInstance(m_ReferenceType));
                }
            }
        }
       #region 回收引用
        public void Release(IReference reference)
        {
        	//在前面的IReference接口中我们定义了一个Clear方法,用来重置对象,具体的重置方法由大家自己实现
            reference.Clear();
            //与上面一样,同样的部分不会在重复
            lock (m_References)
            {
                if (m_References.Contains(reference))
                {
                    throw new GameException("已经存在了该引用!");
                }
                m_References.Enqueue(reference);
            }
        }
        #endregion
        #region 获取引用
        public T Acquire<T>() where T : class, IReference, new()
        {
            if (typeof(T) != m_ReferenceType)
            {
                throw new GameException("该泛型与指定的类型不匹配.");
            }
            lock (m_References)
            {
                if (m_References.Count > 0)
                {
                    return (T)m_References.Dequeue();
                }
            }
            return new T();
        }
        #endregion
        #region 回收引用
        public void Release(IReference reference)
        {
        	//为了复用,需要清空数据
            reference.Clear();
            lock (m_References)
            {
                if (m_References.Contains(reference))
                {
                    throw new GameException("在队列中已经存在了该对象!");
                }
                m_References.Enqueue(reference);
            }
        }
        #endregion
    }
}

4.ReferencePool

在源码中,有private static bool m_EnableStrictCheck这么一句,是用来判断是否需要判断变量的安全,在这就不去写这个变量了,默认就需要判断变量是否安全

public static partial class ReferencePool
{
//上面已经说了一个收集器负责一个类型,那么我们就可以用字典来表示他们的关系进行管理
    private static readonly Dictionary<Type, ReferenceCollection> m_ReferenceCollections = new Dictionary<Type, ReferenceCollection>();
    #region 删除引用
    public static void Remove(Type referenceType,int count)
    {
    	//对传入的Type进行安全检测
        InternalCheckReferenceType(referenceType);
        //利用Type来获取对于的收集器来移除对应数量的对象引用,下面的添加什么的同理
        GetReferenceCollection(referenceType).Remove(count);
    }
    public static void RemoveAll<T>() where T : class,IReference,new()
    {
        GetReferenceCollection(typeof(T)).RemoveAll();
    }
    #endregion
    #region 获取引用
    public static T Acquire<T>() where T : class, IReference, new()
    {
        return GetReferenceCollection(typeof(T)).Acquire<T>();
    }
    #endregion
    #region 回收引用
    public static void Release(IReference reference)
    {
        if (reference == null)
        {
            throw new GameException("对象为空");
        }
        Type referenceType = reference.GetType();
        InternalCheckReferenceType(referenceType);
        GetReferenceCollection(referenceType).Release(reference);
    }
    #endregion
    #region 添加引用
    public static void Add<T>(int count) where T : class, IReference, new()
    {
        GetReferenceCollection(typeof(T)).Add<T>(count);
    }
    #endregion
    private static void InternalCheckReferenceType(Type referenceType)
    {
        if(referenceType == null)
        {
            throw new Exception("报错");
        }
        if(!referenceType.IsClass || referenceType.IsAbstract)
        {
            throw new Exception("报错");
        }
        if (!typeof(IReference).IsAssignableFrom(referenceType)){
            throw new Exception("报错");
        }
    }
    private static ReferenceCollection GetReferenceCollection(Type referenceType)
    {
        if(referenceType == null)
        {
            throw new GameException("报错");
        }
        ReferenceCollection referenceCollection = null;
        lock (m_ReferenceCollections)
        {
            if(!m_ReferenceCollections.TryGetValue(referenceType,out referenceCollection))
            {
                referenceCollection = new ReferenceCollection(referenceType);
                m_ReferenceCollections.Add(referenceType,referenceCollection);
            }
        }
        return referenceCollection;
    }
}

至此我们就只需要创建一个继承接口的类,在测试类中调用ReferencePool中的对应的方法,就可以实现对象池的功能了

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值