作者按:《天天一个设想形式》旨在开端体会设想形式的精华,现在采纳
javascript
和
python
两种言语完成。固然,每种设想形式都有多种完成体式格局,但此小册只纪录最直接了当的完成体式格局 :)
个人手艺博客-godbmw.com 迎接来玩! 每周最少 1 篇原创手艺分享,另有开源教程(webpack、设想形式)、口试刷题(偏前端)、学问整顿(每周细碎),迎接历久关注!本篇博客地点是:《天天一个设想形式之享元形式》。
假如您也想举行学问整顿 + 搭建功用完美/设想简约/疾速启动的个人博客,请直接戳theme-bmw
0. 项目地点
1. 什么是“享元形式”?
享元形式:运用同享手艺来削减建立对象的数目,从而削减内存占用、进步机能。
享元形式提示我们将一个对象的属性划分为内部和外部状况。
- 内部状况:能够被对象鸠合同享,一般不会转变
- 外部状况:依据运用场景常常转变
- 享元形式是应用时候调换空间的优化形式。
2. 运用场景
享元形式虽然名字听起来比较深邃,然则实际运用异常轻易:只如果须要大批建立反复的类的代码块,均能够运用享元形式抽离内部/外部状况,削减反复类的建立。
为了显现它的壮大,下面的代码是简朴地完成了人人耳熟能详的“对象池”,以彰显这类设想形式的魅力。
3. 代码完成
这里应用python
和javascript
完成了一个“通用对象池”类–ObjectPool
。这个类治理一个装载余暇对象的数组,假如外部须要一个对象,直接从对象池中猎取,而不是经由过程new
操纵。
对象池能够大批削减反复建立雷同的对象,从而节省了体系内存,进步运转效力。
为了抽象申明“享元形式”在“对象池”完成和运用,迥殊预备了模仿了File
类,而且模仿了“文件下载”操纵。
经由过程浏览下方代码能够发明:关于File
类,内部状况是pool
属性和download
要领;外部状况是name
和src
(文件名和文件链接)。借助对象池,完成了File
类的复用。
注:为了轻易演示,Javascript
完成的是并发操纵,Python
完成的是串行操纵。输出效果略有不同。
3.1 Python3 完成
from time import sleep
class ObjectPool: # 通用对象池
def __init__(self):
self.__pool = []
# 建立对象
def create(self, Obj):
# 对象池中没有余暇对象,则建立一个新的对象
# 对象池中有余暇对象,直接掏出,无需再次建立
return self.__pool.pop() if len(self.__pool) > 0 else Obj(self)
# 对象接纳
def recover(self, obj):
return self.__pool.append(obj)
# 对象池大小
def size(self):
return len(self.__pool)
class File: # 模仿文件对象
def __init__(self, pool):
self.__pool = pool
def download(self): # 模仿下载操纵
print('+ 从', self.src, '最先下载', self.name)
sleep(0.1)
print('-', self.name, '下载完成')
# 下载终了后,将对象从新放入对象池
self.__pool.recover(self)
if __name__ == '__main__':
obj_pool = ObjectPool()
file1 = obj_pool.create(File)
file1.name = '文件1'
file1.src = 'https://download1.com'
file1.download()
file2 = obj_pool.create(File)
file2.name = '文件2'
file2.src = 'https://download2.com'
file2.download()
file3 = obj_pool.create(File)
file3.name = '文件3'
file3.src = 'https://download3.com'
file3.download()
print('*' * 20)
print('下载了3个文件, 但实在只建立了', obj_pool.size(), '个对象')
输出效果(这里为了轻易演示直接运用了sleep
要领,没有再用多线程模仿):
+ 从 https://download1.com 最先下载 文件1
- 文件1 下载完成
+ 从 https://download2.com 最先下载 文件2
- 文件2 下载完成
+ 从 https://download3.com 最先下载 文件3
- 文件3 下载完成
********************
下载了3个文件, 但实在只建立了 1 个对象
3.2 ES6 完成
// 对象池
class ObjectPool {
constructor() {
this._pool = []; //
}
// 建立对象
create(Obj) {
return this._pool.length === 0
? new Obj(this) // 对象池中没有余暇对象,则建立一个新的对象
: this._pool.shift(); // 对象池中有余暇对象,直接掏出,无需再次建立
}
// 对象接纳
recover(obj) {
return this._pool.push(obj);
}
// 对象池大小
size() {
return this._pool.length;
}
}
// 模仿文件对象
class File {
constructor(pool) {
this.pool = pool;
}
// 模仿下载操纵
download() {
console.log(`+ 从 ${this.src} 最先下载 ${this.name}`);
setTimeout(() => {
console.log(`- ${this.name} 下载终了`); // 下载终了后, 将对象从新放入对象池
this.pool.recover(this);
}, 100);
}
}
/****************** 以下是测试函数 **********************/
let objPool = new ObjectPool();
let file1 = objPool.create(File);
file1.name = "文件1";
file1.src = "https://download1.com";
file1.download();
let file2 = objPool.create(File);
file2.name = "文件2";
file2.src = "https://download2.com";
file2.download();
setTimeout(() => {
let file3 = objPool.create(File);
file3.name = "文件3";
file3.src = "https://download3.com";
file3.download();
}, 200);
setTimeout(
() =>
console.log(
`${"*".repeat(50)}\n下载了3个文件,但实在只建立了${objPool.size()}个对象`
),
1000
);
输出效果以下:
+ 从 https://download1.com 最先下载 文件1
+ 从 https://download2.com 最先下载 文件2
- 文件1 下载终了
- 文件2 下载终了
+ 从 https://download3.com 最先下载 文件3
- 文件3 下载终了
**************************************************
下载了3个文件,但实在只建立了2个对象
4. 参考
- 《JavaScript 设想形式和开辟实践》