游戏框架与组件(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):对象池

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348