享元模式
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();
};
- 文件上传
- 普通方法
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
}
};
- 享元模式重构
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 );
}
}
};