在Unity中我們經常會用到對象池,使用對象池無非就是解決兩個問題:
* 一是減少 new 時候尋址造成的消耗,該消耗的原因是內存碎片。
* 二是減少 Object.Instantiate 時內部進行序列化和反序列化而造成的CPU消耗。
想進一步了解對象池模式優化原理的同學可以參閱: [對象池模式:http://gpp.tkchu.me/object-pool.html](http://gpp.tkchu.me/object-pool.html),本篇主要講如何實現一個精簡并且靈活的對象池。
## 設計:
首先我們要弄清楚本篇對象池的幾個概念,否則直接上代碼大家會一頭霧水。
從字面上理解對象池,池的意思就是容器。我們可以從池中獲取一個對象(一條魚),也可以向池中放入一個對象(一條魚)。獲取的操作我們叫Allocate(分配),而放入一個對象我們叫Recycle(回收)(ps:也有很多習慣叫Spawn 和 Despawn 的,這個看自己習慣了)。所以我們可以定義池的接口為如下:
```cs
public interface IPool<T>
{
T Allocate();
bool Recycle(T obj);
}
```
為什么要用泛型呢?因為筆者開頭說過,本篇主要講如何實現一個精簡并且靈活的對象池。這個靈活很大一部分是通過泛型體現的。
前面有說過,池是容器的意思,在C#中可以是List,Queue或者Stack甚至是數組。所以對象池本身要維護一個容器。本篇我們選取Stack來作為池容器,原因是當我們在Allocate和Recycle時并不關心緩存的存儲的順序,只要求緩存對象的地址是連續的。代碼如下所示:
```cs
using System.Collections.Generic;
public abstract class Pool<T> : IPool<T>
{
...
protected Stack<T> mCacheStack = new Stack<T>();
...
}
```
Pool是個抽象類,為什么呢? 因為筆者開頭說過,本篇主要講如何實現一個精簡并且靈活的對象池。這個靈活很大一部分是通過抽象類體現的。
現在對象的存取和緩存接口都設計好了,那么這些對象是從哪里來的呢?我們分析下,創建對象我們知道有兩種方式,反射構造方法和new一個對象。對象池的一個重要功能就是緩存,要想實現緩存就要求對象可以在對象池內部進行創建。所以我們要抽象出一個對象的工廠,代碼如下所示:
```cs
public interface IObjectFactory<T>
{
T Create();
}
```
那么大家要問為什么要用工廠? 因為筆者開頭說過,本篇主要講如何實現一個精簡并且靈活的對象池。這個靈活很大一部分是通過工廠體現的。
OK,現在對象的創建,存取,緩存的接口都設計好了。下面放出Pool的全部代碼。
```cs
using System.Collections.Generic;
public abstract class Pool<T> : IPool<T>
{
#region ICountObserverable
/// <summary>
/// Gets the current count.
/// </summary>
/// <value>The current count.</value>
public int CurCount
{
get { return mCacheStack.Count; }
}
#endregion
protected IObjectFactory<T> mFactory;
protected Stack<T> mCacheStack = new Stack<T>();
/// <summary>
/// default is 5
/// </summary>
protected int mMaxCount = 5;
public virtual T Allocate()
{
return mCacheStack.Count == 0
? mFactory.Create()
: mCacheStack.Pop();
}
public abstract bool Recycle(T obj);
}
```
代碼不多,設計階段基本就這樣。下面介紹如何實現一個簡易的對象池。
## 對象池實現
首先要實現一個對象的創建器,代碼如下所示:
```cs
using System;
public class CustomObjectFactory<T> : IObjectFactory<T>
{
public CustomObjectFactory(Func<T> factoryMethod)
{
mFactoryMethod = factoryMethod;
}
protected Func<T> mFactoryMethod;
public T Create()
{
return mFactoryMethod();
}
}
```
比較簡單,只是維護了一個返回值為T的委托(如果說得有誤請指正)。
對象池實現:
```cs
using System;
/// <summary>
/// unsafe but fast
/// </summary>
/// <typeparam name="T"></typeparam>
public class SimpleObjectPool<T> : Pool<T>
{
readonly Action<T> mResetMethod;
public SimpleObjectPool(Func<T> factoryMethod, Action<T> resetMethod = null,int initCount = 0)
{
mFactory = new CustomObjectFactory<T>(factoryMethod);
mResetMethod = resetMethod;
for (int i = 0; i < initCount; i++)
{
mCacheStack.Push(mFactory.Create());
}
}
public override bool Recycle(T obj)
{
mResetMethod.InvokeGracefully(obj);
mCacheStack.Push(obj);
return true;
}
}
```
實現也很簡單,這里不多說了。
## 如何使用?
```cs
var fishPool = new SimpleObjectPool<Fish>(() => new Fish(), null, 100);
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
var fishOne = fishPool.Allocate();
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
fishPool.Recycle(fishOne);
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
for (int i = 0; i < 10; i++)
{
fishPool.Allocate();
}
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
```
運行結果:
```cs
fishPool.CurCount:100
fishPool.CurCount:99
fishPool.CurCount:100
fishPool.CurCount:90
```
OK,本篇就介紹到這里
轉載請注明地址:涼鞋的筆記:[liangxiegame.com](http://liangxiegame.com)
## 更多內容
* QFramework 地址:[https://github.com/liangxiegame/QFramework](https://github.com/liangxiegame/QFramework)
* QQ 交流群:[623597263](http://shang.qq.com/wpa/qunwpa?idkey=706b8eef0fff3fe4be9ce27c8702ad7d8cc1bceabe3b7c0430ec9559b3a9ce66)
* **Unity 進階小班**:
* 主要訓練內容:
* 框架搭建訓練(第一年)
* 跟著案例學 Shader(第一年)
* 副業的孵化(第二年、第三年)
* 權益、授課形式等具體詳情請查看[《小班產品手冊》](https://liangxiegame.com/master/intro):https://liangxiegame.com/master/intro
* 關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。

- 正文
- Unity 游戲框架搭建 2017(一)概述
- Unity 游戲框架搭建 2017(二)單例的模板
- Unity 游戲框架搭建 2017(三)MonoBehaviour 單例的模板
- Unity 游戲框架搭建 2017(四)簡易有限狀態機
- Unity 游戲框架搭建 2017(五)簡易消息機制
- Unity 游戲框架搭建 2017 (六) 關于框架的一些好文和一些思考
- Unity 游戲框架搭建 2017 (七) 減少加班利器-QApp類
- Unity 游戲框架搭建 2017 (八) 減少加班利器-QLog
- Unity 游戲框架搭建 2017 (九) 減少加班利器-QConsole
- Unity 游戲框架搭建 2017 (十) QFramework v0.0.2小結
- Unity 游戲框架搭建 2017 (十一) 簡易 AssetBundle 打包工具 (一)
- Unity 游戲框架搭建 2017 (十二) 簡易 AssetBundle 打包工具 (二)
- Unity 游戲框架搭建 2017 (十三) 無需繼承的單例的模板
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (零) QuickStart
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (一) Singleton 單例實現
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (二) MonoSingleton單例實現
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSignleton (三) 通過屬性器實現 Singleton
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (四) 屬性器實現 Mono 單例
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (五) 優雅地進行GameObject命名
- Unity 游戲框架搭建 2017 (十五) 優雅的 QChain (零)
- Unity 游戲框架搭建 2017 (十六) v0.0.3 架構調整
- Unity 游戲框架搭建 2017 (十七) 靜態擴展GameObject 實現鏈式編程
- Unity 游戲框架搭建 2017 (十八) 靜態擴展 + 泛型實現 transform 的鏈式編程
- Unity 游戲框架搭建 2017 (十九) 簡易對象池
- Unity 游戲框架搭建 2017 (二十) 安全的對象池
- Unity 游戲框架搭建 2017 (二十一) 使用對象池時的一些細節
- Unity 游戲框架搭建 2017 (二十二) 簡易引用計數器
- Unity 游戲框架搭建 2017 (二十三) 重構小工具 Platform
- Unity 游戲框架搭建 2017 (二十四) 小結