对象池的管理与设计

对象池的管理与设计

一、什么是对象池

​ 对象池模式(The Object Pool Pattern)是单例模式的一个变种,它提供了获取一系列相同对象实例的入口。当创建过的对象被释放时,这个对象会被放入设计好的池内而非直接销毁,在下次调用此类对象时,会直接去池子中获取已经初始化好的对象,直接省去再次创建对象所消耗的内存。

二、游戏开发实例

​ 拿割草类游戏举例。在一个游戏场景中创建大量怪物,大概100只。玩家使用群攻技能消灭后,完成怪物对象的清除释放。后续又继续加入100只怪物任由玩家攻击。如果使用了对象池,后续的100只怪物并不需要重新创建,只需在先前被消灭的怪物池中复用即可。

三、对象池的管理设计

​ 对象池的管理方式有很多,主要针对对象的类别创建,池子的销毁释放进行管理。这里有一种利用简单工厂和观察者模式进行对象池管理的策略,以下将会此设计进行详细解构:

Obj
ObjGenerator
User
Distributor
IdlePool
UsedPool

对象:Obj

对象。这里需要注意的是,对象池中的访问均是以object类型的key-value实现访问的,这个key可以采用对象生成的hashCode实现,但是Javascript对象不提供hashCode,所以我们借助白鹭引擎Egret中的***egret.HashObject***类来实现。其他语言如有hashCode或给予特定标识key值,则可以无视。由Iobj接口实现,源码如下:

interface IObj
{
    hashc:number; //由于无法重写其get方法,这里只好定义属性进行访问
    type:number; //类型标识
    isIdle:boolean; //标记是否空闲
    dispose():void; //释放对象内部引用
    del():void; //彻底释放对象
    reset():void;   //重置
    setProtocol(val:IDistributor):void; //设置协议
    action():void; //动作
}

/** 对象类型枚举 */
enum ObjType {
    player,
    teammate,
    enemy
}

/** 玩家对象类(实例) */
class Player extends egret.HashObject implements IObj{
	
	private _isIdle:boolean = true;
	private _type:number = ObjType.player;
	private _dis:IDistributor = null;

	private _message:string = "";

	public constructor() {
		super();
	}

	public reset():void
	{
		this._isIdle = false;
		this._dis.distribution( this );

		this._message = "我是玩家";
	}

	public dispose():void
	{
		this._isIdle = true;
		this._dis.distribution( this );

		//other code
	}

	public del():void
	{
		this.dispose();
		this._dis = null;
	}

	public setProtocol( val:IDistributor ):void
	{
		this._dis = val;
	}

	public get type():number
	{
		return this._type;
	}

	public get hashc():number
	{
		return this.hashCode;
	}

	public get isIdle():boolean
	{
		return this._isIdle;
	}

	public action():void
	{
		console.log( this._message );
	}
}

//队友对象类、敌人对象类略...

分配器:Distributor

对象分配器。只负责对象的存储管理,同时作为对象的协议实现。由以下IDistributor接口实现,源码如下:

interface IDistributor
{
    distribution(val:IObj):void; //分配
    addVO(val:IObj):void; //添加元素
    getVO(type:number):IObj; //获取元素
    clear():void; //清除所有未使用的对象
}

class Distributor implements IDistributor
{
	private _UsedPool:Object = null; //使用中的对象
	private _IdlePool:Object = null; //未使用的对象

	public constructor()
	{
		this._IdlePool = {};
		this._UsedPool = {};
	}

	public distribution( val:IObj ):void
	{
		if( val.isIdle )
		{
			this._IdlePool[ val.hashc ] = val;
			delete this._UsedPool[ val.hashc ];
		}
		else
		{
			this._UsedPool[ val.hashc ] = val;
			delete this._IdlePool[ val.hashc ];
		}
	}

	public addVO( val:IObj ):void
	{
		val.setProtocol( this );
		if( val.isIdle )
		{
			this._IdlePool[ val.hashc ] = val;
			
		}
		else
		{
			this._UsedPool[ val.hashc ] = val;
		}
	}

	public getVO( type:number ):IObj
	{
		let obj:IObj = null;
		for (let key in this._IdlePool) {
			obj = this._IdlePool[key] as IObj;
			if ( obj.type == type ) {
				obj.reset();
				return obj;
			}
		}
		return null;
	}

	public clear():void
	{
		let obj:IObj = null;
		for (let key in this._IdlePool) {
			obj = this._IdlePool[key] as IObj;
			obj.del();
		}
		this._IdlePool = null;
		this._IdlePool = {};
	}
}

分配器内分有两个池,被使用池和空闲池。当用户需要新的对象时,会在空闲池中寻找,存在同类对象则会初始化后返回,同时加入被使用池中。不存在同类对象返回空值,以此告知生成器需要生成新的对象。

一旦对象不再被使用,则放入空闲池中。

clear方法可以清除空闲池中所有的对象,达到清除内存的目的。

生成器:ObjGenerator

对象生成器。使用简单工厂模式,按类型给对象进行创建生成,不参与创建后的对象存储分配,只开放对象的获取方法。源码如下:

class ObjGenerator 
{
	private _dis:IDistributor = null;

	public constructor( val:IDistributor ) 
	{
		this.init( val );
	}

	private init( val:IDistributor ):void
	{
		this._dis = val;
	}

	public getObj( type:number ):IBall
	{
		let vo:IObj = this._dis.getVO( type );
		if( vo == null )
		{
			vo = this.createVO( type );
			this._dis.addVO( vo );
			vo.reset();
		}
		return vo;
	}

	private createVO( type:number ):IObj
	{
		switch( type )
		{
			case ObjType.player:
				return new Player(); //主角
			case ObjType.teammate:
				return new TeamMate(); //队友
			case ObjType.enemy:
				return new Enemy(); //敌人
		}
	}
}

客户端演示

class Main extends egret.DisplayObjectContainer
{

    public constructor() {
        super();

        this.init();
    }

    private _gen:ObjGenerator = null;
    private init()
    {
        this._gen = new ObjGenerator(new Distributor());

        let role:Player = this._gen.getBall(ObjType.player) as Player; //生成玩家对象,对象被使用
        role.action(); //玩家执行动作逻辑

        role.dispose();//不再使用,加入空闲池
        role = null; //玩家对象销毁
        
        let role2:Player = this._gen.getBall(ObjType.player) as Player; //再次生成玩家对象,但此时的对象是在空闲池中返回,可对比role的key值进行验证
    }
}

四、总结

利用简单工厂和观察者模式,可以将对象池中对象生成与存储分配进行分离。用户只需操作对象的生成,将内存持久化权限交由分配器处理。在必要的时候还可以使用分配器提供的clear方法彻底释放内存(例如游戏切换场景,关卡结束)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值