享元模式
享元模式是一种用于性能优化的模式,享元模式的核心就是运用共享技术来有效支持大量细粒度的对象。享元模式要求将对象的属性划分为内部状态和外部状态。享元模式的目标就是尽量减少共享对象的数量。
怎样划分内部状态和外部状态?
- 内部状态存储于对象内部
- 内部状态可以被一些对象共享
- 内部状态独立于具体场景,通常不会改变
- 外部状态取决于具体的场景,并根据场景变化,外部状态不能被共享
这样一来,我们便可以把所有内部状态都相同的对象都指定为同一个共享对象。而外部状态可以从对象身上剥离,并存储在外部。
比如,当我们需要模特分别为500种男士衣服和500种女士衣服打广告,在最坏的情况下我们可以用500名男/女模特,分别穿上500种不同的衣服,但是这样显然是不好的;因为我们可以只使用1名男/女模特依次穿上500种不同的衣服。在这里性别就可以划分为内部状态,不同的衣服就可以划分为外部状态。
例子
<script>
let id = 0
window.startUpload = function (uploadType, files) {
files.forEach(file => {
let uploadObj = new Upload(uploadType, file.fileName, file.fileSize)
uploadObj.init(id++)
});
}
let Upload = function (type, name, size) {
this.uploadType = type
this.fileName = name
this.fileSize = size
this.dom = null
}
Upload.prototype.init = function (id) {
let that = this
this.id = id
this.dom = document.createElement('div')
this.dom.innerHTML =
`
<span>文件名:${this.fileName},文件大小:${this.fileSize}
<button class="delFile">删除</button>
`
this.dom.querySelector('.delFile').onclick = function () {
that.delFile()
}
document.body.appendChild(this.dom)
}
Upload.prototype.delFile = function () {
if (this.fileSize < 3000) {
return this.dom.parentNode.removeChild(this.dom)
}
if (window.confirm(`are you sure delete file of ${this.fileName}`)) {
return this.dom.parentNode.removeChild(this.dom)
}
}
startUpload('plugin', [{
fileName: 1,
fileSize: 1000,
},{
fileName: 2,
fileSize: 2000,
},{
fileName: 3,
fileSize: 3000,
},{
fileName: 4,
fileSize: 4000,
}])
</script>
在上面的这个例子中我们发现我们有多少个文件就会创建多少个对象,这样的情况下如果需要创建大量的文件浏览器就会吃不消。所以我们分析代码,发现uploadType
是内部状态,因为当浏览器确定上传方式也就确定了,fileName;fileSize
是外部状态因为不同的文件的名称和大小不同。所以我们将uploadType
作为内部对象从构造函数中剥离出来。
对象池
对象池维护一个装载空闲对象的池子,如果需要对象的时候,不是直接new,而是转而从对象池中获取,如果对象池没有空闲的对象,则创建一个新的对象,当获取出的对象完成它的职责之后,在进入池子等待下次被获取。