1.享元模式要求将对象的属性划分为内部状态与外部状态。享元模式的目标是尽量减少共享对象的数量,下面是关于如何划分内部状态和外部状态的指引
1)内部状态存储于对象内部
2)内部状态可以被一些对象共享
3)内部状态独立于具体的场景,通常不会改变
4)外状态取决于具体的场景,并根据场景而变化,外部状态不能被共享
这样一来我们就可以把所有内部状态相同的对象都指定为同一个共享对象,而外部状态可以从对象身上剥离出来,并存储在外部
代码实现(1.文件上传,上传文件可以排对一个一个的上传,也支持同时选择2000个文件。每一个文件对应着一个js上传对象的创建)
var id = 0;
window.startUpload = function(uploadType,files){
for(var i = 0,file;file = files[i++]){
var uploadObj = new Upload(uploadType,file.fileName,fileSize);
uploadobj.init(id++) //给upload对象设置一个唯一的ID
}
}
//定义Upload构造函数
var Upload = function(uploadType,fileName,fileSize){
this.uploadType = uploadType;
this.fileName = fileName;
this.fileSize = fileSize;
this.dom = null
}
Upload.prototype.init = function(id){
var that = this;
this.id = id;
this.dom = document.creanElement('div');
this.dom.innerHTML = '<span>文件名称:'+ this.fileName +', 文件大小: '+ this.fileSize +'</span>' +
'<button class="delFile">删除</button>';
this.dom.querySelector('.delFIle').onclick = function(){
that.delFile();
}
document.body.appendChild( this.dom );
}
Upload.prototype.delFile = function(){
if ( this.fileSize < 3000 ){
return this.dom.parentNode.removeChild( this.dom );
}
if ( window.confirm( '确定要删除该文件吗? ' + this.fileName ) ){
return this.dom.parentNode.removeChild( this.dom );
}
};
//享元模式重构文件上传
//上段代码有多少个需要上传的文件,就一共创建了多少个upload对象,现在我们用享元模式来重构
//剥离外部状态
var Upload = function(uploadType){
this.uploadType = uploadType;
}
Upload.prototype.delFile = function(id){
uploadManager.setExternalState( id, this ); // (1)
if ( this.fileSize < 3000 ){
return this.dom.parentNode.removeChild( this.dom );
}
if ( window.confirm( '确定要删除该文件吗? ' + this.fileName ) ){
return this.dom.parentNode.removeChild( this.dom );
}
}
//工厂进行对象实例化
var UploadFactory = (function(){
var createdFlyWeightObjs = {};
return {
create: function( uploadType){
if ( createdFlyWeightObjs [ uploadType] ){
return createdFlyWeightObjs [ uploadType];
}
return createdFlyWeightObjs [ uploadType] = new Upload( uploadType);
}
}
})();
//管理器封装外部状态
var uploadManager = (function () {
var uploadDatabase = {};
return {
add: function (id, uploadType, fileName, fileSize) {
var flyWeightObj = UploadFactory.create(uploadType);
var dom = document.createElement('div');
dom.innerHTML =
'<span>文件名称:' + fileName + ', 文件大小: ' + fileSize + '</span>' +
'<button class="delFile">删除</button>';
dom.querySelector('.delFile').onclick = function () {
flyWeightObj.delFile(id);
}
document.body.appendChild(dom);
uploadDatabase[id] = {
fileName: fileName,
fileSize: fileSize,
dom: dom
};
return flyWeightObj;
},
setExternalState: function (id, flyWeightObj) {
var uploadData = uploadDatabase[id];
for (var i in uploadData) {
flyWeightObj[i] = uploadData[i];
}
}
}
})();
//开始触发上传动作的 startUpload 函数:
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 );
}
};
现在同事上传2000个文件,需要创建的upload对象数量依然是2
2.对象池:对象池维护一个装载空闲对象的池子。如果需要对象,不是直接new,而是转从对象池里获取。如果对象池为空,则创建一个新的对象,当获取出的对象完成它的职责之后,在进入池子等待下次被获取
代码实现(这里我们并没有主动分离内部状态喝外部状态的过程)
//对象池实现
var toolTipFactory = (function(){
var toolTipArr = [];
return{
create:function(){
if(toolTipArr.length === 0){
let obj = {};
return obj;
}else{
return toolTipArr.shift();
}
},
recover:function(toolTip){
toolTipArr.push(toolTip)
}
}
})()
//用数组记录我们创建了的toolTip
let arr = [];
for(var i = 0; i < 2; i++){
let toolTipObj = toolTipFactory.create();
toolTipObj.title = `hello${i}`;
arr.push(toolTipObj);
}
//回收创建的2个toolTip
for(var i = 0; i < 2; i++){
toolTipFactory.recover(arr[i]);
}
//创建4个toolTip,其中将有2个是我们之前创建的
arr = [];
for(var i = 0; i < 4; i++){
let toolTipObj = toolTipFactory.create();
toolTipObj.name = `hello${i}`;
arr.push(toolTipObj);
}
//验证 之前的2个toolTip带有title属性
arr.forEach(item=> console.log(item))
//打印结果
{ title: 'hello0', name: 'hello0' }
{ title: 'hello1', name: 'hello1' }
{ name: 'hello2' }
{ name: 'hello3' }
//对象池事另外一种性能优化方案,它跟享元模式有一些相似之处,但没有分离内部状态喝外部状态这个过程
总结:享元模式事为解决性能问题而生的模式,这跟大部分模式诞生的原因都不一样,在一个存在大量相似对象的系统中,享元模式可以很好的解决大量对象带来的性能问题
网友评论