JS设计模式之享元模式

享元模式解决创建大量类似对象而导致的性能问题。

示例:

一个汽车类

//汽车登记示例
   var Car =function(make,model,year,owner,tag,renewDate){
     this.make=make;
     this.model=model;
     this.year=year;
     this.owner=owner;
     this.tag=tag;
     this.renewDate=renewDate;
   }
   Car.prototype = {
     getMake:function(){
       returnthis.make;
     },
     getModel:function(){
       returnthis.model;
     },
     getYear:function(){
       returnthis.year;
     },
     transferOwner:function(owner,tag,renewDate){
       this.owner=owner;
       this.tag=tag;
       this.renewDate=renewDate;
     },
     renewRegistration:function(renewDate){
       this.renewDate=renewDate;
     }
   }

拥有品牌、型号、出产日期三个内在属性,三个外在属性车主、车牌最近登记日期。

三个内在属性定义的组合,只需要一个对象即可。

新版Car类代码

//包含核心数据的Car类
   var Car=function(make,model,year){
     this.make=make;
     this.model=model;
     this.year=year;
   }
   Car.prototype={
     getMake:function(){
       returnthis.make;
     },
     getModel:function(){
       returnthis.model;
     },
     getYear:function(){
       returnthis.year;
     }
   }

用工厂模式实例化

//中间对象,用来实例化Car类
   var CarFactory=(function(){
     var createdCars = {};
     return {
       createCar:function(make,model,year){
                 if(createdCars[make+"-"+model+"-"+year]){
				    return  createdCars[make+"-"+model+"-"+year];
				 }else{
				    var car=new Car(make,model,year);
            createdCars[make +'-'+ model +'-'+ year] = car;
                    return car
				 }         
       }
     }
   })();
管理外在装态
//数据工厂,用来处理Car的实例化和整合附加数据
   var CarRecordManager = (function() {
     var carRecordDatabase = {};
     return {
       addCarRecord:function(make,model,year,owner,tag,renewDate){
         var car = CarFactory.createCar(make, model, year);
         carRecordDatabase[tag]={
           owner:owner,
           tag:tag,
           renewDate:renewDate,
           car:car
       }
     },
       transferOwnership:function(tag, newOwner, newTag, newRenewDate){
         var record=carRecordDatabase[tag];
         record.owner = newOwner;
         record.tag = newTag;
         record.renewDate = newRenewDate;
       },
       renewRegistration:function(tag,newRenewDate){
         carRecordDatabase[tag].renewDate=newRenewDate;
       },
       getCarInfo:function(tag){
         return carRecordDatabase[tag];
       }
     }
   })();
通过carRecordDatabase这个对象将内在对象与外在对象整合起来,享元对象与其所属的方法集中管理。相当于是哪一类型的车是一个对象,然后这个对象与其余的外在对象关联,减少对象的声明。

Web日历

不用享元模式,用组合模式包装,然后要创建365个CalendarDay对象,一年的话

var CalendarYear = function(year, parent){
		this.year = year;
		this.element = document.createElement('div');
		this.element.style.display = 'none';
		parent.appendChild(this.element);
		function isLeapYear(y){
		    return (y>0)&&!(y%4)&&((y%100)||!(y%400));
		}
		
		this.months = [];
		this.numDays = [31,isisLeapYear(this.year)?29:28,31,30,31,30,31,31,30,31,30,31];
		for(var i = 0,len = 12; i<len; i++){
		    this.months[i] = new CalendarMonth(i, this.numDays[i], this.element);
		}
	};
	
	CalendarYear.prototype = {
	    display:function(){
		    for(var i = 0, len = this.months.length; i<len; i++){
			    this.months[i].display();
			}
			this.element.style.dispaly = 'block';
		}
	};
	
	var CalendarMonth = function(monthNum, numDays, parent){
	    this.monthNum = monthNum;
		this.element = document.createElement('div');
		this.element.style.display = 'none';
		parent.appendChild(this.element);
		
		this.days = [];
		for(var i = 0, len = this.days.length; i < len; i++){
		    this.days[i] = new CalendarDay(i, this.element);
		}
	};
	
	CalendarMonth.prototype = {
	    display:function(){
		    for(var i = 0, len = this.days.length; i<len; i++){
			    this.days[i].display();
			}
			this.element.style.dispaly = 'block';
		}
	};
	
	var CalendarDay = function(date, parent){
	    this.date = date;
		this.element = document.createElement('div');
		this.element.style.display = 'none';
		parent.appendChild(this.element);
	};
	
	CalendarDay.prototype = {
	    display: function(){
		    this.element.style.display = 'block';
			this.element.innerHTML = this.date;
		}
	};

用享元模式

var CalendarDay = function(){};
	
	CalendarDay.prototype = {
	    display: function(date, parent){
		    var element = document.createElement('div');
			parent.appendChild(element);
			element.innerHTML = date;
		}
	};
	
	var calendarDay = new CalendarDay();
创建单个实例,以前的构造参数成为display的方法参数,然后修改CalendayMonth

var CalendarMonth = function(monthNum, numDays, parent){
	    this.monthNum = monthNum;
		this.element = document.createElement('div');
		this.element.style.display = 'none';
		parent.appendChild(this.element);
		
		this.days = [];
		for(var i = 0, len = this.days.length; i < len; i++){
		    this.days[i] = calendarDay;
		}
	};
	
	CalendarMonth.prototype = {
	    display:function(){
		    for(var i = 0, len = this.days.length; i<len; i++){
			    this.days[i].display(i, this.element);
			}
			this.element.style.dispaly = 'block';
		}
	};

将公用一个类,只是类的方法参数不同。这样内在数据只是calendarDay这个对象,外在对象日期等保存在组合对象的结构本身。

这样组合对象的叶对象只包含少量数据,就抽离出来,转化为共享资源。


var Tooltip = function(targetElement, text){
	    this.target = targetElement;
		this.text = text;
		this.delayTimeout = null;
		this.delay = 1500;
		
		this.element = document.createElement('div');
		this.element.style.display = 'none';
		this.element.style.position = 'absolute';
		this.element.className = 'tooltip';
		document.getElementsByTagName('body')[0].appendChild(this.element);
		this.element.innerHTML = this.text;
		
		var that = this;
		addEvent(this.target, 'mouseover', function(e){that.startDelay(e);});
		addEvent(this.target, 'mouseout', function(e){that.hide();});
	};
	
	Tooltip.prototype = {
	    startDelay:function(e){
		    if(this.delayTimeout == null){
			    var that = this;
				var x = e.clientX;
				var y = e.clientY;
				this.delayTimeout = setTimeout(function(){
				    this.show(x,y);
				},this.delay);
			}
		},
		show:function(x, y){
		    clearTimeout(this.delayTimeout);
			this.delayTimeout = null;
			this.element.style.left = x + 'px';
			this.element.style.top = y + 'px';
			this.element.style.display = 'block';
		},
		hide:function(){
		    clearTimeout(this.delayTimeout);
			this.delayTimeout = null;
			this.element.style.display = 'none';
		}
	};

使用享元模式

var Tooltip = function(){
		this.delayTimeout = null;
		this.delay = 1500;
		
		this.element = document.createElement('div');
		this.element.style.display = 'none';
		this.element.style.position = 'absolute';
		this.element.className = 'tooltip';
		document.getElementsByTagName('body')[0].appendChild(this.element);
	};
	
	Tooltip.prototype = {
	    startDelay:function(e, text){
		    if(this.delayTimeout == null){
			    var that = this;
				var x = e.clientX;
				var y = e.clientY;
				this.delayTimeout = setTimeout(function(){
				    this.show(x, y, text);
				},this.delay);
			}
		},
		show:function(x, y, text){
		    clearTimeout(this.delayTimeout);
			this.delayTimeout = null;
			this.element.innerHTML = text;
			this.element.style.left = x + 'px';
			this.element.style.top = y + 'px';
			this.element.style.display = 'block';
		},
		hide:function(){
		    clearTimeout(this.delayTimeout);
			this.delayTimeout = null;
			this.element.style.display = 'none';
		}
	};

享元对象,将外在数据先全部剔除。

var TooltipManager = (function(){
	    var storeInstance = null;
		var Tooltip = function(){
			this.delayTimeout = null;
			this.delay = 1500;
			
			this.element = document.createElement('div');
			this.element.style.display = 'none';
			this.element.style.position = 'absolute';
			this.element.className = 'tooltip';
			document.getElementsByTagName('body')[0].appendChild(this.element);
		};
		
		Tooltip.prototype = {
			startDelay:function(e, text){
				if(this.delayTimeout == null){
					var that = this;
					var x = e.clientX;
					var y = e.clientY;
					this.delayTimeout = setTimeout(function(){
						this.show(x, y, text);
					},this.delay);
				}
			},
			show:function(x, y, text){
				clearTimeout(this.delayTimeout);
				this.delayTimeout = null;
				this.element.innerHTML = text;
				this.element.style.left = x + 'px';
				this.element.style.top = y + 'px';
				this.element.style.display = 'block';
			},
			hide:function(){
				clearTimeout(this.delayTimeout);
				this.delayTimeout = null;
				this.element.style.display = 'none';
			}
	    };
		
		return  {
		    addTooltip:function(targetElement, text){
			    var tt = this.getTooltip();
				addEvent(targetElement, 'mouseover', function(e){that.startDelay(e);});
		        addEvent(targetElement, 'mouseout', function(e){that.hide();});
			},
			getTooltip:function(){
			    if(storeInstance == null){
				    storeInstance = new Tooltip();
					return storeInstance;
				}
			}
		};
	})();

外在对象被闭包保存。


保存实例供以后重用

var DialogBox = function(){};
	DialogBox.prototype = {
	    show:function(header, body, footer){},
	    hide:function(){},
		state:function(){}
	};
	DialogBoxManager = (function(){
	    var created = [];
		return {
		    displayDialogBox:function(header, body, footer){
			    var inUse = this.numberInUse();
				if(inUse > created.length){
				    created.push(this.createDialogBox());
				}
				created[inUse].show(header, body, footer);
			},
			createDialogBox:function(){
			    var db = new DialogBox();
				return db;
			},
			numberInUse:function(){
			    var inUse = 0;
				for(var i = 0, len = created.length; i < len; i++){
				    if(created[i].state = 'visible'){
					    inUse++;
					}
				}
				return inUse;
			}
		};
	})();

这里将创建出的DialogBox保存在created这个闭包变量中,然后获取正在被使用的个数,如果都被使用,就创建,否则就重用。

这样内在对象就就一直被重用,然后外在对象保存在闭包变量中,这里复杂了一下,就相当与数据库的连接池。

享元模式使用的场合:

第一:网页中使用了大规模的密集对象。

第二:这些对象的内部数据能够分离出来,作为参数提供给方法。

第三:分离出的内在的对象比较少,尽量减少独一无二的对象。

享元模式的一般步骤:

1、将所有外在数据从目标类中剥离。尽量删除该类的属性跟构造函数,然后提供给该类的方法。结果是功能一样,数据的来源与方法的参数。

2、创建一个控制该类的实例化工厂,保存创造出的独一无二的对象。一种方法是用一个对象保存引用,然后用参数的唯一指定索引,另一种是对象池,用数组保存引用。

3、创建保存外在数据的管理器。把内在数据提供给工厂对象以创造对象,外在数据保存在管理器的数据结构中。

享元模式之利:

降低网页负荷。

享元模式之弊:

只是在一系列条件下满足的优化,然后创造的对象变少,追踪数据问题困难,维护困难。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值