享元模式

减少对象的数量,将对象属性划分为内部状态和外部状态。
内衣广告拍摄例子,将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 );
    }
};

  • 对象池
    需要用一个对象时,不是直接new 一个对象,先去对象池里拿,用完后再放回对象池。如果,对象池没有了对象,就再创建一个。
    使用场景:避免频繁创建和删除DOM节点。
    对象池:一般有创建对象和回收对象俩个方法。
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 );

        }
    }
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容