JS设计模式之享元模式
2013-10-23 00:34
411 查看
享元模式解决创建大量类似对象而导致的性能问题。
示例:
一个汽车类
拥有品牌、型号、出产日期三个内在属性,三个外在属性车主、车牌最近登记日期。
三个内在属性定义的组合,只需要一个对象即可。
新版Car类代码
用工厂模式实例化
管理外在装态
通过carRecordDatabase这个对象将内在对象与外在对象整合起来,享元对象与其所属的方法集中管理。相当于是哪一类型的车是一个对象,然后这个对象与其余的外在对象关联,减少对象的声明。
Web日历
不用享元模式,用组合模式包装,然后要创建365个CalendarDay对象,一年的话
用享元模式
创建单个实例,以前的构造参数成为display的方法参数,然后修改CalendayMonth
将公用一个类,只是类的方法参数不同。这样内在数据只是calendarDay这个对象,外在对象日期等保存在组合对象的结构本身。
这样组合对象的叶对象只包含少量数据,就抽离出来,转化为共享资源。
使用享元模式
享元对象,将外在数据先全部剔除。
外在对象被闭包保存。
保存实例供以后重用
这里将创建出的DialogBox保存在created这个闭包变量中,然后获取正在被使用的个数,如果都被使用,就创建,否则就重用。
这样内在对象就就一直被重用,然后外在对象保存在闭包变量中,这里复杂了一下,就相当与数据库的连接池。
享元模式使用的场合:
第一:网页中使用了大规模的密集对象。
第二:这些对象的内部数据能够分离出来,作为参数提供给方法。
第三:分离出的内在的对象比较少,尽量减少独一无二的对象。
享元模式的一般步骤:
1、将所有外在数据从目标类中剥离。尽量删除该类的属性跟构造函数,然后提供给该类的方法。结果是功能一样,数据的来源与方法的参数。
2、创建一个控制该类的实例化工厂,保存创造出的独一无二的对象。一种方法是用一个对象保存引用,然后用参数的唯一指定索引,另一种是对象池,用数组保存引用。
3、创建保存外在数据的管理器。把内在数据提供给工厂对象以创造对象,外在数据保存在管理器的数据结构中。
享元模式之利:
降低网页负荷。
享元模式之弊:
只是在一系列条件下满足的优化,然后创造的对象变少,追踪数据问题困难,维护困难。
示例:
一个汽车类
//汽车登记示例 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 4000 (){ 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、创建保存外在数据的管理器。把内在数据提供给工厂对象以创造对象,外在数据保存在管理器的数据结构中。
享元模式之利:
降低网页负荷。
享元模式之弊:
只是在一系列条件下满足的优化,然后创造的对象变少,追踪数据问题困难,维护困难。
相关文章推荐
- js设计模式之结构型享元模式详解
- 【js设计模式笔记---享元模式】
- 【js设计模式笔记---享元模式】
- js设计模式(8)---享元模式
- JS设计模式之享元模式
- JS常用的设计模式(16)—— 享元模式
- js 设计模式学习--观察者模式
- 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)
- js设计模式之构造函数
- JS设计模式之工厂模式
- 代码回忆录 - js设计模式 - 二〇一八年三月七日 - 1
- js设计模式总结1
- [设计模式](八):组合模式(Composite)与享元模式(Flyweight)详解
- 23种设计模式--结构型模式(适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式)
- 深入理解JavaScript系列(37):设计模式之享元模式详解
- js的面向对象和设计模式
- 设计模式之享元模式
- 设计模式之享元模式
- 善用设计模式-享元模式
- node.js笔记之订阅发布设计模式