每日一个设计模式(二)——享元模式

引子

上次我们讲了观察者模式,这次我们再来讲一个常见的模式,称为享元模式。

理论

看看维基百科上对享元模式的定义:

享元模式(英语:Flyweight Pattern)是一种软件设计模式>)。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。

这个定义可能看起来比较拗口,实际上我们再日常中可能不知不觉就用到了享元模式的思想,我们可以把享元模式类比为现在的共享经济,例如某个共享单车存放点有 n 辆单车,那么当用户需要时,我们就将单车借出去,用户用完了,就把单车还回来,如果用户来借单车时没有单车了,就从仓库拿出新单车,这样的话,就能通过少量单车数量满足大量用户使用了。

代码实现

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class Bike {
constructor(num) {
this.no = num;
}

use() {
console.log("The bike " + this.no + " is using!");
}
}

const BikeRenter = (function () {
let bike = [];
let store = 0;
let sum = 0;
return {
getBike: function () {
if (store < 1) {
bike.push(new Bike(sum + 1));
sum++;
return bike.pop();
} else {
store--;
return bike.pop();
}
},
reBike: function (b) {
bike.push(b);
store++;
},
};
})();

class People {
constructor(name) {
this.name = name;
this.bike = null;
}

borrow() {
this.bike = BikeRenter.getBike();
console.log(this.name + " borrowed the NO." + this.bike.no + " bike.");
}

re() {
BikeRenter.reBike(this.bike);
this.bike = null;
}

use() {
if (this.bike) {
this.bike.use();
}
}
}

const a = new People("aaa");
const b = new People("bbb");
const c = new People("ccc");

a.borrow(); // "aaa borrowed the NO.1 bike."
a.use(); //"The bike 1 is using!"
b.borrow(); //"bbb borrowed the NO.2 bike."
b.use(); //"The bike 2 is using!"
a.re();
c.borrow(); // "ccc borrowed the NO.1 bike."
c.use(); //"The bike 1 is using!"

上面就是一个很简单的共享单车例子,我们通过一个单车管理中心来调度,这个例子中 3 个人都使用了单车,但是实际上我们的工厂只生产了两辆单车,类比到我们平时代码中就是减少了内存占用。

前端中的应用

前端中我们最容易碰到的需求就是大容量列表,假设我们有一个 30w 行的列表需要滚动展示,如何让这个列表滚动时不会觉得有明显卡顿?

因为滚动过程中会请求数据,不断的将数据读到浏览器中,也就会有更多的内存占用,如果不做处理很容易出现卡顿和页面崩溃,这里我们就可以用到享元模式的方法。

我们在滚动展示页面的时候,不直接生产 DOM,而是去某个Renter里面获取,如果Renter里有,就直接掉出来展示,如果没有再创建新的,在列表滚动过程中,已经滚动过去的也不删除,而是放在 Renter 里,这样,在有大量重复数据的情况下,我们实际所需要产生的 DOM 数量就会明显减少。

总结

享元模式比较适合大量对象非常消耗内存,同时对象里有些东西重复的情况下使用,使用享元模式要注意抽离出最小的享元,多场景复用。

参考文献

享元模式

作者

bert_cai

发布于

2019-04-26

更新于

2020-11-16

许可协议

评论