对象池系列

对象池系列(一)

对象池的核心思想:预先初始化一组可重用的实体,而不是按需销毁然后重建。每次要用的时候都去创建用完就销毁掉,会造成频繁的资源回收;

首先应该有基本的两个方法生产Spawn回收Despawn.假如我们需要对子弹Bullet进行Spawn和Despawn处理。于是我们定义了一个IPool接口和Pool类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IPool
{
    Bullet Spwan();
    void Despawn(Bullet bullet);
}
public class Pool : IPool
{
    private Stack<Bullet> cacheStack = new Stack<Bullet>();

    public Bullet Spwan()
    {
        return cacheStack.Count > 0 ? cacheStack.Pop() : new Bullet();
    }
    public void Despawn(Bullet bullet)
    {
        cacheStack.Push(bullet);
    }
}

最基本的Bullet对象池就创建好了,那么来看看有什么问题?1.对于扩展极不方便,如果需要增加一个其他类似于子弹这样的对象池,我们还需要去增加额外的例如IPool和Pool这样的脚本,所以这里想到的应该是利用泛型。代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IPool<T>
{
    T Spwan();
    void Despawn(T obj);
}
public class Pool<T> : IPool<T>
{
    private Stack<T> cacheStack = new Stack<T>();

    public T Spwan()
    {
        return cacheStack.Count > 0 ? cacheStack.Pop() : default(T);
    }
    public void Despawn(T obj)
    {
        cacheStack.Push(obj);
    }
}

到这里我们解决了扩展的问题。我们再来看看还有什么问题?假如我创建子弹的时候需要额外的参数应该怎么办?这里的Default(T)就不在适用了,这里到底是在干什么?我们首先得弄清楚,在上一个版本中这里是new Bullet()对象,而现在这里是给一个默认的对象。总而言之这里是在创建一个新的对象。根据功能来看这里需要返回一个T类型的对象,但是具体返回一个什么样的对象,我们是不知道的,也就是说这里的细节应该在于子类去完成,所以这里应该抽象化(细节依赖于抽象)。首先我想到的就是接口,其次这里的功能是创建对象,提到"创建"我就想到了工厂。所以这里增加了一个IFactory这样的Interface.代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IPool<T>
{
    T Spwan();
    void Despawn(T obj);
}
public interface IFactory<T>
{
    T Create();
}
public class Pool<T> : IPool<T>
{
    private Stack<T> cacheStack = new Stack<T>();
    private IFactory<T> factory;
    public T Spwan()
    {
        return cacheStack.Count > 0 ? cacheStack.Pop() : factory.Create();
    }
    public void Despawn(T obj)
    {
        cacheStack.Push(obj);
    }
}

我们再来看看如何,Pool声明了一个IFactory的引用factory,而原来的Default(T)被替换成了factory.Create().到了这里唯一没有确定的就是facotry该如何传进来,首先想到的就是构造器。代码如下:增加了一个构造函数需要传进来一个IFactory的对象。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IPool<T>
{
    T Spwan();
    void Despawn(T obj);
}
public interface IFactory<T>
{
    T Create();
}
public class Pool<T> : IPool<T>
{
    private Stack<T> cacheStack = new Stack<T>();
    private IFactory<T> factory;
    public Pool(IFactory<T> factory)
    {
        this.factory = factory;
    }
    public T Spwan()
    {
        return cacheStack.Count > 0 ? cacheStack.Pop() : factory.Create();
    }
    public void Despawn(T obj)
    {
        cacheStack.Push(obj);
    }
}

到了这里可以算是初步完成了,但是我们再来思考一下,如果我每次增加一个例如类似于BulletPool这样的对象池,我还需要额外增加一个实现了IFacotry接口的类,这样增加了客户端的使用麻烦。所以我这个时候就想到了怎么样才能把额外增加的实现了IFacotry接口的类省去,于是我们再来看看IFactory这个接口到底做了什么事情?原来如此,它就是负责一件事情,对象的创建!!!所以这里我们可以把factory对象的创建转移到内部。代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IPool<T>
{
    T Spwan();
    void Despawn(T obj);
}
public interface IFactory<T>
{
    T Create();
}
public class ObjectFactory<T> : IFactory<T>
{
    private Func<T> _createMethod;
    public ObjectFactory(Func<T> createMethod)
    {
        _createMethod = createMethod;
    }
    public T Create()
    {
        return _createMethod();    
    }
}

public class Pool<T> : IPool<T>
{
    private Stack<T> cacheStack = new Stack<T>();
    private IFactory<T> factory;
    public Pool(Func<T> createObjectMethod)
    {
        factory = new ObjectFactory<T>(createObjectMethod);
    }
    public T Spwan()
    {
        return cacheStack.Count > 0 ? cacheStack.Pop() : factory.Create();
    }
    public void Despawn(T obj)
    {
        cacheStack.Push(obj);
    }
}

这样factory对象的创建就转移到了内部,客户端不再需要去额外增加类。到这里差不多就算完成了。但是我们再来看看还有没有需要完善的地方,果真如此。这里这个Despawn()方法再我看来还需要修改修改,比如Unity中GameObject我在回收掉之前想做一些特殊处理,例如gameObject.SetActive(false)之类的操作。我们发现对于不同对象的回收,他们可能都有着不一样的地方,对于不一样的地方,那么就应该抽象。所以我认为这里可以将Despawn这个方法抽象化,也就是实现为抽象方法。代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IPool<T>
{
    T Spwan();
    void Despawn(T obj);
}
public interface IFactory<T>
{
    T Create();
}
public class ObjectFactory<T> : IFactory<T>
{
    private Func<T> _createMethod;
    public ObjectFactory(Func<T> createMethod)
    {
        _createMethod = createMethod;
    }
    public T Create()
    {
        return _createMethod();    
    }
}

public abstract class Pool<T> :  IPool<T>
{
    protected Stack<T> cacheStack = new Stack<T>();
    protected IFactory<T> factory;
    public T Spwan()
    {
        return cacheStack.Count > 0 ? cacheStack.Pop() : factory.Create();
    }
    public abstract void Despawn(T obj);
}
public class ObjectPool<T> : Pool<T>
{
    protected Action<T> _resetMethod;
    public ObjectPool(Func<T> createMethod,Action<T> resetMethod)
    {
        factory = new ObjectFactory<T>(createMethod);
        _resetMethod = resetMethod;
    }
    public override void Despawn(T obj)
    {
        _resetMethod?.Invoke(obj);
        cacheStack.Push(obj);
    }
}
public class BulletPoolManager :  MonoBehaviour
{
    public ObjectPool<Bullet> BulletPool;
    public GameObject BulletPrefab;
    private void Awake()
    {
        BulletPool = new ObjectPool<Bullet>(() => Instantiate(BulletPrefab).GetComponent<Bullet>(), bullet => bullet.gameObject.SetActive(false));
    }
}

至于具体BulletPoolManager或者其他Manager怎么使用,是单例还是怎么样,都看自己需求。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值