UFL3-2——缓存池具体实现
UFL3-2——缓存池具体实现
缓存池具体实现
-
创建
PoolManager
继承 不继承MonoBehaviour的单例模式基类1
2
3
4
5
6
7/// <summary>
/// 缓存池模块 管理器
/// </summary>
public class PoolManager : BaseManager<PoolManager>
{
private PoolManager() { }
} -
声明柜子(
Dictionary
)和抽屉(List
、Stack
、Queue
等)容器1
2
3
4
5
6
7
8
9
10/// <summary>
/// 缓存池模块 管理器
/// </summary>
public class PoolManager : BaseManager<PoolManager>
{
//柜子容器当中有抽屉的体现
private Dictionary<string, Stack<GameObject>> poolDic = new Dictionary<string, Stack<GameObject>>();
private PoolManager() { }
} -
拿东西方法
GetObj
- 有抽屉并且抽屉里有东西 直接获取
- 没有抽屉或者抽屉里没东西 创造
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 缓存池模块 管理器
/// </summary>
public class PoolManager : BaseManager<PoolManager>
{
//柜子容器当中有抽屉的体现
private Dictionary<string, Stack<GameObject>> poolDic = new Dictionary<string, Stack<GameObject>>();
private PoolManager() { }
/// <summary>
/// 拿东西的方法
/// </summary>
/// <param name="name">抽屉容器的名字</param>
/// <returns>从缓存池中取出的对象</returns>
public GameObject GetObj(string name)
{
GameObject obj;
//有抽屉,且抽屉内有对象
if (poolDic.ContainsKey(name) && poolDic[name].Count > 0)
{
obj = poolDic[name].Pop();
obj.SetActive(true);
}
//否则,就应该去创建对象
else
{
obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
}
return obj;
}
} -
放东西方法
PushObj
- 有抽屉,直接放
- 没抽屉,创建抽屉,再放
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 缓存池模块 管理器
/// </summary>
public class PoolManager : BaseManager<PoolManager>
{
//柜子容器当中有抽屉的体现
private Dictionary<string, Stack<GameObject>> poolDic = new Dictionary<string, Stack<GameObject>>();
private PoolManager() { }
/// <summary>
/// 往缓存池中放入对象
/// </summary>
/// <param name="name">抽屉(对象池)的名字</param>
/// <param name="obj">要放入的对象</param>
public void PushObj(string name, GameObject obj)
{
//并不是直接移除对象,而是将对象失活一会再用,用的时候再激活它
//除了失活对象,还可以通过把对象放到很远的地方等方式来隐藏对象(失活的性能可能偏低一些)
obj.SetActive(false);
//如果不存在对应的抽屉容器,先创建抽屉,再往抽屉内放
if (!poolDic.ContainsKey(name))
poolDic.Add(name, new Stack<GameObject>());
poolDic[name].Push(obj);
}
/// <summary>
/// 拿东西的方法
/// </summary>
/// <param name="name">抽屉容器的名字</param>
/// <returns>从缓存池中取出的对象</returns>
public GameObject GetObj(string name)
{
GameObject obj;
//有抽屉,且抽屉内有对象
if (poolDic.ContainsKey(name) && poolDic[name].Count > 0)
{
obj = poolDic[name].Pop();
obj.SetActive(true);
}
//否则,就应该去创建对象
else
{
obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
}
return obj;
}
} -
清空柜子方法
ClearPool
我们在切场景时,对象都会被移除,这时应该清空柜子,否则会出现内存泄漏,并且下次取东西会出问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 缓存池模块 管理器
/// </summary>
public class PoolManager : BaseManager<PoolManager>
{
//柜子容器当中有抽屉的体现
private Dictionary<string, Stack<GameObject>> poolDic = new Dictionary<string, Stack<GameObject>>();
private PoolManager() { }
/// <summary>
/// 清除整个柜子当中的数据
/// </summary>
public void ClearPool()
{
poolDic.Clear();
}
/// <summary>
/// 拿东西的方法
/// </summary>
/// <param name="name">抽屉容器的名字</param>
/// <returns>从缓存池中取出的对象</returns>
public GameObject GetObj(string name)
{
GameObject obj;
//有抽屉,且抽屉内有对象
if (poolDic.ContainsKey(name) && poolDic[name].Count > 0)
{
obj = poolDic[name].Pop();
obj.SetActive(true);
}
//否则,就应该去创建对象
else
{
obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
}
return obj;
}
/// <summary>
/// 往缓存池中放入对象
/// </summary>
/// <param name="name">抽屉(对象池)的名字</param>
/// <param name="obj">要放入的对象</param>
public void PushObj(string name, GameObject obj)
{
//并不是直接移除对象,而是将对象失活一会再用,用的时候再激活它
//除了失活对象,还可以通过把对象放到很远的地方等方式来隐藏对象(失活的性能可能偏低一些)
obj.SetActive(false);
//如果不存在对应的抽屉容器,先创建抽屉,再往抽屉内放
if (!poolDic.ContainsKey(name))
poolDic.Add(name, new Stack<GameObject>());
poolDic[name].Push(obj);
}
}
缓存池测试
实现一个按下鼠标左键或右键就从缓存池内分别取出两种对象,取出的对象过一秒后就压入池内
按照一定频率反复按下鼠标左键和右键,观察两种对象场景上的数量是否最后是恒定的
对象从池内取出时执行的脚本
1 | using UnityEngine; |
调用缓存池的脚本
1 | using System; |
按照一定频率反复按下鼠标左键和右键,场景上创建的两种对象数量在一定时间后不再增长,被创建出来的对象不会被销毁而是被复用:
压入方法参数优化
假设要让 PushObj
方法只需要传入需要被压入池内的对象这一个参数,而不需要传入对象所在的名字(路径)
而原来这个传入的名字(路径)是用来确认对象需要压入到哪个池子的
因此,我们可以通过传入的对象的名字,来确认压入到哪个池子内,如果没有这个池子,就根据传入的名字创建对应的缓存池
值得一提的是,由于GameObject.Instantiate
方法克隆出来的对象名字会自带一个(clone)
,
因此我们需要在创建对象的时候,手动让对象的名字等于GetObj
方法传入的对象的名字
1 | using System.Collections; |
因此,调用 PushObj
方法不再需要额外传入对象的路径
1 | using UnityEngine; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 文KRIFE齐的博客!