对象池背后的理念其实是非常简单的。我们将对象存储在一个池子中,当需要时在再次使用,而不是每次都实例化一个新的对象。池的最重要的特性,也就是对象池设计模式的本质是允许我们获取一个“新的”对象而不管它真的是一个新的对象还是循环使用的对象。
我们游戏中大量用到了对象池。
今天看了下对象池底层的代码。下面这篇文章写得挺好
废话不多说,上我们自己的对象池代码。
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// 清0操作由调用者负责编写
// 提供对非unity对象的缓存,即逻辑对象缓存
// 注意必须是class哈
// 提供接口 IObjectClear, Release时自动调用
public interface IObjectClear
{
void Clear();
}
public class ObjectPool
{
class ObjectGroup
{
public Stack<object> m_freeStack;
public int m_iMaxNum; // 最大数量,为0表示不限制,否则超过最大数量,Release时直接delete
public ObjectGroup()
{
m_freeStack = new Stack<object>();
m_iMaxNum = 0;
}
}
Dictionary< Type, ObjectGroup > m_typeDic;
object m_locker = new object();
bool m_bIsthreadSafe;
public ObjectPool(bool bIsthreadSafe = false)
{
m_typeDic = new Dictionary< Type, ObjectGroup >();
m_bIsthreadSafe = bIsthreadSafe;
}
public void Register<T>( int iInitNum, int iMaxNum = 0 ) where T : class, new()
{
if (iInitNum < 0)
{
throw new ArgumentException("Init num < 0");
}
ObjectGroup group = null;
if ( m_typeDic.TryGetValue(typeof(T), out group) )
{
// 已存在
return;
}
group = new ObjectGroup();
group.m_iMaxNum = iMaxNum;
if (iInitNum > 0)
{
for (int i = 0; i < iInitNum; i++)
{
T obj = new T();
if (m_bIsthreadSafe)
{
lock (m_locker)
{
group.m_freeStack.Push(obj);
}
}
else
{
group.m_freeStack.Push(obj);
}
}
}
m_typeDic[typeof(T)] = group;
}
public T Get<T>() where T : class, new()
{
ObjectGroup group = null;
if (!m_typeDic.TryGetValue(typeof(T), out group))
{
Register<T>(1);
return Get<T>();
}
T obj = null;
if (0 == group.m_freeStack.Count)
{
obj = new T();
}else
{
if (m_bIsthreadSafe)
{
lock (m_locker)
{
obj = group.m_freeStack.Pop() as T;
}
}
else
{
obj = group.m_freeStack.Pop() as T;
}
}
return obj;
}
public void Release<T>(T obj) where T : class, new()
{
if (null == obj)
{
throw new ArgumentException("obj is null!!");
}
ObjectGroup group = null;
Type t = ((object)obj).GetType();
if (!m_typeDic.TryGetValue(t, out group))
{
throw new ArgumentException("obj's type is not registered!");
}
if (obj is IObjectClear)
{
((IObjectClear)obj).Clear();
}
if (group.m_iMaxNum > 0 && group.m_freeStack.Count >= group.m_iMaxNum)
{
if (obj is IDisposable)
{
((IDisposable)obj).Dispose();
}
obj = null;
System.GC.Collect();
}
else
{
// add to free list
if (m_bIsthreadSafe)
{
lock (m_locker)
{
group.m_freeStack.Push(obj);
}
}
else
{
group.m_freeStack.Push(obj);
}
}
}
private void _DestroyGroup( ObjectGroup group )
{
object obj = null;
while (group.m_freeStack.Count > 0)
{
if (m_bIsthreadSafe)
{
lock (m_locker)
{
obj = group.m_freeStack.Pop();
}
}
else
{
obj = group.m_freeStack.Pop();
}
if (obj is IDisposable)
{
((IDisposable)obj).Dispose();
}
obj = null;
}
if (m_bIsthreadSafe)
{
lock (m_locker)
{
group.m_freeStack.Clear();
}
}
else
{
group.m_freeStack.Clear();
}
}
public void DestroyType<T>() where T : class, new()
{
ObjectGroup group = null;
if (!m_typeDic.TryGetValue(typeof(T), out group))
{
throw new ArgumentException("obj's type is not registered!");
}
this._DestroyGroup(group);
}
// destroy所有实列
public void DestroyAll()
{
foreach (var it in m_typeDic)
{
ObjectGroup group = it.Value;
this._DestroyGroup(group);
group = null;
}
m_typeDic.Clear();
System.GC.Collect();
}
}