设计模式之享元模式

什么是享元模式

享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。

文件上传的例子

上传文件方法比如浏览器插件、Flash 和表单上传等,为了简化例子,我们先假设只有插件和 Flash 这两种。不论是插件上传,还是 Flash 上传,原理都是一样的,当用户选
择了文件之后,插件和 Flash 都会通知调用 Window 下的一个全局 JavaScript 函数,它的名字是startUpload,用户选择的文件列表被组合成一个数组 files 塞进该函数的参数列表里,代码如下:

var id = 0;
window.startUpload = function( uploadType, files ){ // uploadType 区分是控件还是 flash
 for ( var i = 0, file; file = files[ i++ ]; ){
 var uploadObj = new Upload( uploadType, file.fileName, file.fileSize );
 uploadObj.init( id++ ); // 给 upload 对象设置一个唯一的 id
 }
}; 

当用户选择完文件之后,startUpload 函数会遍历 files 数组来创建对应的 upload 对象。接下来定义 Upload 构造函数,它接受 3 个参数,分别是插件类型、文件名和文件大小。这些信息都已经被插件组装在 files 数组里返回,代码如下:

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.createElement( '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 );
 }
}; 

接下来分别创建 3 个插件上传对象和 3 个 Flash 上传对象:

startUpload( 'plugin', [
 {
   fileName: '1.txt',
   fileSize: 1000
 },
 {
   fileName: '2.html',
   fileSize: 3000
 },
 {
   fileName: '3.txt',
   fileSize: 5000
 }
]);
startUpload( 'flash', [
 {
   fileName: '4.txt',
   fileSize: 1000
 },
 {
   fileName: '5.html',
   fileSize: 3000
 },
 {
   fileName: '6.txt',
   fileSize: 5000
 }
]); 

享元模式重构文件上传:
明确了 uploadType 作为内部状态之后,我们再把其他的外部状态从构造函数中抽离出来,Upload 构造函数中只保留 uploadType 参数:

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 );
 }
}; 
startUpload( 'plugin', [
 {
   fileName: '1.txt',
   fileSize: 1000
 },
 {
   fileName: '2.html',
   fileSize: 3000
 },
 {
   fileName: '3.txt',
   fileSize: 5000
 }
]);
startUpload( 'flash', [
 {
   fileName: '4.txt',
   fileSize: 1000
 },
 {
   fileName: '5.html',
   fileSize: 3000
 },
 {
   fileName: '6.txt', 
   fileSize: 5000
 }
]); 
posted @ 2021-11-29 09:12  自在一方  阅读(55)  评论(0编辑  收藏  举报