游戏框架与组件(1):对象池

本文介绍了对象池以及对象池的代码实现。

本文链接  游戏框架与组件(1):对象池

一、为什么需要对象池

        对象池和内存池类似。都是为了解决对象创建、销毁和复用的问题。

        内存池中,频繁new申请内存,会造成两个问题。

        (1)new操作很耗性能

        (2)频繁申请的内存块,造成大量内存碎片

        所以内存池就是用来解决这个问题的。内存池至少提供了两个机制

        (1)根据算法将预先申请好的大内存块,分成很多个级别的小内存块供程序申请。

        (2)优先复用已回收的、合适的对象

        以上机制解决了new操作和内存碎片的问题。

        对象池和内存池类似。主要解决频繁新建和销毁对象性能消耗及对象复用的问题。

二、对象池设计

        实现对象池需要解决以下几个问题。

        1、对象池管理器。管理器的新建、销毁问题。新增对象池、销毁对象池接口

        2、对象池。对象池新建、销毁、新增某类对象合、销毁某类对象集合

        3、池对象类。继承于池对象类的对象,自身拥有从池中创建、回收到池中的接口。受对象池管理。

        4、未继承于池对象类的对象,则有对象池来显示进行新建和回收操作。

        图示(1/2)如下:


对象池及管理器

    图示(2/2)如下,UML类图关系。


对象池UML类图


三、对象池实现

        我们以TypeScript语言为例来实现对象池。

        1、我们先实现ObjectPool对象池类。

export class ObjectPool<T> {

    public static NAME: string = "ObjectPool";

    /** 存储表 */

    private pool: HashTable<T[]> = null;

    constructor() {

        this.pool = new HashTable<T[]>();

    }

    /** 

     * 回收对象接口

     * @param object 对象

     * @param key 对象标识

     * @param recoverHandler 激活时需要执行的回调

     * @param limitCount 池中允许缓存的最大数量

     * @param recoverHandler 池中对象满时的回调

     */

    public pushObject(object: T, key: string | number, recoverHandler?: Function, limitCount: number = 0, limitHandler?: Function): void {

        if (!object || this.isInPool(object)) {

            logger.error(this, "对象为空或已存在于内存池中, 回收失败", object, key);

            return;

        }

        if (!key) {

            logger.error(this, "对象的key为空, 回收失败", object, key);

        }else {

            let objList = this.pool.get(key);

            if (!objList) {

                objList = [];

                this.pool.insert(key, objList);

            }

            if (limitCount == 0 || objList.length < limitCount) {

                objList.push(object);

            }else {

                if (limitHandler) {

                    if (typeof limitHandler == "function") {

                        limitHandler(object);

                    }

                }

                return;

            }

            object["__is_in_pool"] = true;

            let recoverFunc = object["onRecoverToPool"];

            if (recoverFunc && typeof recoverFunc == "function") {

                (recoverFunc as Function).bind(object)();

            }

            if (recoverHandler) {

                if (typeof recoverHandler == "function") {

                    recoverHandler(object);

                }

            }

        }

    }

    /** 

     * 获取池对象接口

     * @param key 对象标识

     * @param createFunction 创建函数

     * @param awakeHandler 池中对象被取出激活时,需要处理的回调

     * @param ...args 对象构造函数需要传的参数

     */

    public getObject(key: string | number, createFunction?: Function, awakeHandler?: (poolObject: any) => void, ...args): T {

        let retObj: T = null;

        if (this.size(key) > 0) {

            if (key) {

                let objList = this.pool.get(key);

                if (objList) {

                    if (objList.length > 0) {

                        retObj = objList.pop();

                        if (objList.length == 0) {

                            // 删除数据

                            this.pool.delete(key);

                        }

                    }

                }

            }else {

                logger.error(this, "获取对象的key不能为空");

                return;

            }

        }

        if (!retObj && createFunction) {

            let newObject = createFunction() as T;

            retObj = newObject;

        }

        if (retObj) {

            if (retObj["__is_in_pool"] == false) {

                logger.error(this, "获取的对象状态错误!", retObj);

            }

            retObj["__is_in_pool"] = false;

            let awakeFunc = retObj["onAwakeFromPool"];

            if (awakeFunc && typeof awakeFunc == "function") {

                (awakeFunc as Function).bind(retObj)();

            }

            if (awakeHandler) {

                if (typeof awakeHandler == "function") {

                    retObj && awakeHandler(retObj);

                }

            }

        }

        return retObj;

    }

    /** 

     * 删除对象

     */

    public removeObject(removeObj: T, key: string | number, destroyFunc?: Function): void {

        let objs = this.pool.get(key);

        if (objs && objs.length > 0) {

            for (let i = 0; i < objs.length; i++) {

                const obj = objs[i];

                if (obj == removeObj) {

                    objs.splice(i, 1);

                    if (destroyFunc) {

                        destroyFunc(removeObj);

                    }

                    return;

                }

            }

        }

    }

    /** 

     * 查询池对象组接口

     * @param key 对象标识

     */

    public queryObjects(key: string | number): T[] {

        let retObjs: T[] = [];

        if (this.size(key) > 0) {

            if (key) {

                retObjs = this.pool.get(key) || retObjs;

            }else {

                logger.error(this, "获取对象的key不能为空");

            }

        }

        return retObjs;

    }

    /** 

     * 获取对象数量 

     * @param key 对象标识

     */

    public size(key: string | number): number {

        let objList = this.pool.get(key);

        if (objList) {

            return objList.length;

        }

        return 0;

    }

    /** 

     * 获取所有对象数组

     * @param key 对象标识

     */

    public asArray(key?: string | number): T[] {

        if (key) {

            return this.pool.get(key) || [];

        }else {

            let size = this.pool.size();

            if (size > 0) {

                let ret = [];

                this.pool.foreach2(function(_key: string, obj: T) {

                    let subObjs = this.pool.get(_key) || [];

                    for (let i = 0; i < subObjs.length; i++) {

                        ret.push(subObjs[i]);

                    }

                }.bind(this));

                return ret;

            }

        }

        return [];

    }

    /** 是否在对象池中 */

    public isInPool(object: T): boolean {

        if (!object) {

            return false;

        }

        return !!object["__is_in_pool"];

    }

    /** 获取所有key列表 */

    keys() {

        return this.pool.keys();

    }

}

        2、实现对象池管理类ObjectPoolManager

export class ObjectPoolMgr {

    /** 单例对象 */

    private static __instance: ObjectPoolMgr = null;

    /** 对象池类型表 */

    private poolTypeTable: HashTable<ObjectPool<any>> = null;

    private constructor() {

        this.poolTypeTable = new HashTable<ObjectPool<any>>();

    }

    public static getInstance() {

        if (!ObjectPoolMgr.__instance) {

            ObjectPoolMgr.__instance = new ObjectPoolMgr();

        }

        return ObjectPoolMgr.__instance;

    }

    /** 

     * 创建一个对象池

     * 

     */

    protected createPool<T>(key: string, creator?: Function): ObjectPool<T> {

        let newPool = creator ? creator() : new ObjectPool<T>();

        this.poolTypeTable.insert(key, newPool);

        return newPool;

    }

    /** 

     * 获取一个对象池

     * 

     */

    public static getPool<T>(key?: string, creator?: Function): ObjectPool<T> {

        let pool = ObjectPoolMgr.getInstance().poolTypeTable.get(key);

        if (!pool) {

            pool = ObjectPoolMgr.getInstance().createPool<T>(key, creator);

        }

        return pool;

    }

    /** 销毁对象池 */

    public removePool(key: string): void {


    }

    /** 获取对象数量 */

    public size(): number {

        return this.poolTypeTable.size();

    }

}

        3、池对象类PoolObject

export class PoolObject extends HashCode {

    public static NAME:string = "PoolObject";

    public static _poolKey: string = PoolObject.NAME;

    public static _pool: any = ObjectPoolMgr.getPool(PoolObject._poolKey);

    public static _classRefCache = {};

    public static _objectMap: {key?: [number]} = {};

    public static _objectIDMap: {key?: [number]} = {};

    constructor() {

        super();

    }

    /**

     * 获取是否在对象池中

     */

    public isInPool(): boolean {

        return PoolObject._pool.isInPool(this);

    }

    /**

     * 获取对象

     * @param classRef 类

     * @param createFunction 自定义创建函数,返回对象

     * @param awakeHandler 池中对象被取出激活时,需要处理的回调

     * @param ...args 对象构造函数需要传的参数

     */

    public static createFromPool<T>(classRef: new (...args: any[]) => T, createFunction?: (...args: any[]) => T, awakeHandler?: (poolObject: T) => void, disableReConstructor: boolean = false, ...args): T {

        let key = getFunctionId(classRef);

        let createFunc = createFunction;

        if (createFunction) {

            createFunc = () => {

                let newObj = createFunction(...args);

                let objFid = getFunctionId(newObj.constructor);

                PoolObject._objectIDMap[objFid] = key;

                PoolObject._objectMap[key] = (PoolObject._objectMap[key] || 0) + 1;

                return newObj;

            };

        }else {

            createFunc = () => {

                let newObj = new classRef(...args);

                let objFid = getFunctionId(newObj.constructor);

                PoolObject._objectIDMap[objFid] = key;

                PoolObject._objectMap[key] = (PoolObject._objectMap[key] || 0) + 1;

                return newObj;

            };

        }

        let _awakeHandler = (poolObj: T) => {

            if (!disableReConstructor) {

                poolObj.constructor(...args);

            }

            awakeHandler && awakeHandler(poolObj);

        }

        return PoolObject._pool.getObject(key, createFunc, _awakeHandler, ...args);

    }

    /**

     * 回收对象

     */

    public recoverToPool(recoverHandler?: Function): void {

        if (this.isInPool()) {

            return;

        }

        let objFid = getFunctionId(this.constructor);

        let key = PoolObject._objectIDMap[objFid];

        PoolObject._pool.pushObject(this, key, recoverHandler);

    }

    /** 

     * 获取池中对象数量

     */

    public static getPoolObjectCount<T>(classRef: new (...args: any[]) => T): number {

        return (PoolObject._pool as ObjectPool<T>).size(getFunctionId(classRef));

    }

    /** 

     * 获取对象总数量

     */

    public static getObjectTotalCount<T>(classRef: new (...args: any[]) => T): number {

        let id = getFunctionId(classRef);

        return PoolObject._objectMap[id] || 0;

    }

}


本文链接  游戏框架与组件(1):对象池

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。