享元模式

2018-07-05  本文已影响0人  bby365

减少对象的数量,将对象属性划分为内部状态和外部状态。
内衣广告拍摄例子,将100个对象变成2个对象。

// 每次都创建一个对象
for ( var i = 1; i <= 50; i++ ){
        var maleModel = new Model( 'male', 'underwear' + i );
        maleModel.takePhoto();
};
// 只创建一个对象,再给对象添加一个变化的属性
for ( var i = 1; i <= 50; i++ ){
        maleModel.underwear = 'underwear' + i;
        maleModel.takePhoto();
};
  1. 普通方法
window.startUpload = function( uploadType, files ){ 
    for ( var i = 0, file; file = files[ i++ ]; ){
        // 每次都会创建一个新对象
        var uploadObj = new Upload( uploadType, file.fileName, file.fileSize );
        uploadObj.init( id++ ); // 给upload 对象设置一个唯一的id
    }
};
  1. 享元模式重构
    uploadType划为内部状态,文件相关信息抽离为外部状态。
    2.1 定义Upload
// 1. 不会直接调用Upload
var Upload = function( uploadType){
        this.uploadType = uploadType;
};

// 2. 使用工厂实例化,这样每种类型只会创建一个对象
var UploadFactory = (function(){
        var createdFlyWeightObjs = {};
        return {
            create: function( uploadType){
                if ( createdFlyWeightObjs [ uploadType] ){
                    return createdFlyWeightObjs [ uploadType];
                }
                return createdFlyWeightObjs [ uploadType] = new Upload( uploadType);
            }
        }
})();

2.2 外部状态管理器
只有需要时,才调用管理器方法

var uploadManager = (function(){
    var uploadDatabase = {};
    return {
        add: function( id, uploadType, fileName, fileSize ){
            var flyWeightObj = UploadFactory.create( uploadType );
            // 处理逻辑...

            // 将外部信息保存
            uploadDatabase[ id ] = {
                fileName: fileName,
                fileSize: fileSize,
                dom: dom
            };
            
            return flyWeightObj ;
        },
        // 获取外部状态信息
        setExternalState: function( id, obj ){
            var uploadData = uploadDatabase[ id ];
            for ( var i in uploadData ){
                obj[ i ] = uploadData[ i ];
            }
        }
    }
})();

2.3 上传函数

var id = 0;
window.startUpload = function( uploadType, files ){
    for ( var i = 0, file; file = files[ i++ ]; ){
        // 不是直接调用构造函数,使用的是外部管理器方法
        var uploadObj = uploadManager.add( ++id, uploadType, file.fileName, file.fileSize );
    }
};

var toolTipFactory = (function(){
    var toolTipPool = []; // toolTip 对象池
    return {
        create: function(){
            if ( toolTipPool.length === 0 ){ 
                var div = document.createElement( 'div' ); 
                document.body.appendChild( div );
                recovereturn div;
            }else{ 
                return toolTipPool.shift(); 
            }
        },
        recover: function( tooltipDom ){
            return toolTipPool.push( tooltipDom ); 
        }
    }
})();

1. 如果使用中并没有主动调用回收方法,
那么对象池中就不会存储之前创建的对象

集中使用方法:

var ary = [];
for ( var i = 0, str; str = [ 'A', 'B' ][ i++ ]; ){
    var toolTip = toolTipFactory.create();
    toolTip.id = str // 便于辨别是否为对象池中对象
    toolTip.innerHTML = str;
    ary.push( toolTip );
};
// 没有回收对象,后面将创建6个对象,而不是4个
for ( var i = 0, toolTip; toolTip = ary[ i++ ]; ){
    toolTipFactory.recover( toolTip );
};

for ( var i = 0, str; str = [ 'A', 'B', 'C', 'D', 'E', 'F' ][ i++ ]; ){
    var toolTip = toolTipFactory.create();
    toolTip.innerHTML = str;
};

如果把具体的创建过程封装起来,就会实现通用对象池。

// createObjFn 是具体的创建对象函数,又外部传入
var objectPoolFactory = function( createObjFn ){
    var objectPool = [];
    return {
        create: function(){
            var obj = objectPool.length === 0 ?
            createObjFn.apply( this, arguments ) : objectPool.shift();
            return obj;
        },
        recover: function( obj ){
            objectPool.push( obj );

        }
    }
};
上一篇下一篇

猜你喜欢

热点阅读