js设计模式-享元模式

享元模式

享元模式是一种用于性能优化的模式,如果系统中因为创建了大量类似的对象而导致内存不足或占用过高这种模式就非常有用了。
下面通过具体的实例来看看。

假设有个内衣工厂,目前的产品有50种男士内衣与50种女士内衣,为了推销产品,工厂决定生产一些塑料模特来穿上它们的内衣拍成内衣广告。
正常情况需要50个男模特与50个女模特,然后让他们每人分别穿上一套内衣来拍照。不使用享元模式可能会有这种方式来写:

内衣厂展示许多商品

方案一:造 50 个塑料男模和 50 个塑料女模,让他们穿上展示,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Model = function (sex,underwear) {
this.sex = sex;
this.underwear = underwear;
}
Model.prototype.takePhoto = function () {
console.log('sex=' + this.sex + 'underwear=' + this.underwear )
}
for (var i = 1; i <=50; i++){
var maleModel = new Model('male','underwear' + i)
maleModel.takePhoto();
}
for (var i = 1; i <=50; i++){
var maleModel = new Model('female','underwear' + i)
femaleModel.takePhoto();
}

方案二:造 1 个塑料男模特 1 个塑料女模特,分别试穿 50 款内衣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Model = function (sex) {
this.sex = sex;
}
Model.prototype.takePhoto = function () {
console.log('sex=' + this.sex + 'underwear=' + this.underwear )
}


var maleModel = new Model('male'),
female = new Model('female');
for (var i = 1; i <=50; i++){
maleModel.underwear = 'underwear' + i;
maleModel.takePhoto();
}
for (var i = 1; i <=50; i++){
female.underwear = 'underwear' + i;
femaleModel.takePhoto();
}

对比发现:方案一创建了 100 个对象,方案二只创建了 2 个对象,在该 demo 中,gender(性别) 是内部对象,underwear(穿着) 是外部对象。

对象池

对象池维护一个装载空闲对象的池子,如果需要对象的时候,不是直接new,而是转从对象池里获取对象。如果对象池里没有空闲对象则创建一个新的对象,当获取的对象完成他的职责之后,再进入池子等待被下次获取。
对象池的原理很好理解,下面我们从地图应用来理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 气泡工厂的对象池为数组是私有属性被包含在工厂闭包里,这个工厂又两个暴露对外的方法,
// create表示获取一个div节点,recover表示回收一个div节点。

var toolTipFactory = (function () {
var toolTipPool = []; // toolTip 对象池
return {
create : function () {
if(toolTipPool.length === 0){
var div = document.createElement('div');
document.body.appendChild(div);
return div;
} else{
return toolTipPool.shift(); //shift a dom
},
recover : function (tooltipDom) {
return toolTipPool.push(tooltipDom);
}
}
}
})();


// 第一次搜索(2个气泡)
var ary = [];
for(var i = 0, str; str = ['A','B'][i++]){ // get ary elem
var toolTip = toolTipFactory.create();
toolTip.innerHTML = str;
ary.push(toolTip)

};


// 现在开始回收节点:
for(var i = 0 , toolTip ; toolTip = ary[i++]){
toolTip.recover(toolTip)
}
// 第二次搜索(6个气泡)
for(var i =0 , str; str = ['A','B','C','D','E','F'][i++]; ){
var toolTip = toolTipFactory.create();
toolTip.innerHTML(str);
}

现在页面中已经出现了6个节点,上一次创建好的节点被共享给了下一次操作。

Buy me a cup of coffee,thanks!