从使用者视角给出需求
首先,我所希望的这个内存池的代码最后使用应该是这样的。
Bullet a = Pool.Take(); //从池中立刻获取一个单元,如果单元不存在,则它需要为我立刻创建出来。返回一个Bullet脚本以便于后续控制。注意这里使用泛型,也就是说它应该可以兼容任意的脚本类型。
Pool.restore(a);//当使用完成Bullet之后,我可以使用此方法回收这个对象。注意这里实际上我已经把Bullet这个组件的回收等同于某个GameObject(这里是子弹的GameObject)的回收。
使用上就差不多是这样了,希望可以有极其简单的方法来进行获取和回收操作。
内存池单元结构
最简单的内存池形式,差不多就是两个List,一个处于工作状态,一个处于闲置状态。工作完毕的对象被移动到闲置状态列表,以便于后续的再次获取和利用,形成一个循环。我们这里也会设计一个结构来管理这两个List,用于处理同一类的对象。
接下来是考虑内存池单元的形式,我们考虑到内存池单元要尽可能容易扩展,就是可以兼容任意数据类型,也就是说,假设我们的内存池单元定为Pool_Unit,那么它不能影响后续继承它的类型,那我们最好使用接口,一旦使用类,那么就已经无法兼容Unity组件,因为我们自定义的Unity组件全部继承自MonoBehavior。接下来考虑这个内存单元该具有的功能,差不多有两个基本功能要有:
restore();//自己主动回收,为了方便后续调用,回收操作最好自己就有。
getState();//获取状态,这里是指获取当前是处于工作状态还是闲置状态,也是一个标记,用于后续快速判断。因为接口中无法存储单元,这里使用变通的方法,就是留给实现去处理,接口中要求具体实现需要提供一个状态标记。
综合内存池单元和状态标记,给出如下代码:
namespace AndrewBox.Pool
{
public interface Pool_Unit
{
Pool_UnitState state();
void setParentList(object parentList);
void restore();
}
public enum Pool_Type
{
Idle,
Work
}
public class Pool_UnitState
{
public Pool_Type InPool
{
get;
set;
}
}
}
单元组结构
接下来考虑单元组,也就是前面所说的针对某一类的单元进行管理的结构。它内部有两个列表,一个工作,一个闲置,单元在工作和闲置之间转换循环。它应该具有以下功能:
创建新单元;使用抽象方法,不限制具体创建方法。对于Unity而言,可能需要从Prefab克隆,那么最好有方法可以从指定的Prefab模板复制创建。
获取单元;从闲置表中查找,找不到则创建。
回收单元;将其子单元进行回收。
综合单元组结构的功能,给出如下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AndrewBox.Pool
{
public abstract class Pool_UnitList where T:class,Pool_Unit
{
protected object m_template;
protected List m_idleList;
protected List m_workList;
protected int m_createdNum = 0;
public Pool_UnitList()
{
m_idleList = new List();
m_workList = new List();
}
///
/// 获取一个闲置的单元,如果不存在则创建一个新的
///
/// 闲置单元
public virtual T takeUnit() where UT:T
{
T unit;
if (m_idleList.Count > 0)
{
unit = m_idleList[0];
m_idleList.RemoveAt(0);
}
else
{
unit = createNewUnit();
unit.setParentList(this);
m_createdNum++;
}
m_workList.Add(unit);
unit.state().InPool = Pool_Type.Work;
OnUnitChangePool(unit);
return unit;
}
///
/// 归还某个单元
///
/// 单元
public virtual void restoreUnit(T unit)
{
if (unit!=null && unit.state().InPool == Pool_Type.Work)
{
m_workList.Remove(unit);
m_idleList.Add(unit);
unit.state().InPool = Pool_Type.Idle;
OnUnitChangePool(unit);
}
}
///
/// 设置模板
///
///
///
public void setTemplate(object template)
{
m_template = template;
}
protected abstract void OnUnitChangePool(T unit);
protected abstract T createNewUnit() where UT : T;
}
}
更多unity2018的功能介绍请到paws3d爪爪学院查找。