js享元模式

106 阅读1分钟

适用场景(主要是用于性能优化)

  • 一个程序中使用了大量的相似对象
  • 由于使用了大量对象,造成很大的内存开销
  • 对象的大多数状态都可以变为外部状态
  • 剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象

典型的使用场景——文件上传

//剥离外部状态(文件的名称、大小等),保留不变的内部状态(上传方式)
class Upload {
    constructor(uploadType) {
        this.uploadType = uploadType
    }
    delFile(id) {
        // 动态的赋予外部属性
        uploadManager.setExternalState(id, this)
        if (this.fileSize < 3000) {
                return this.dom.parentNode.removeChild(this.dom)
        }
        if (window.confirm("确定要删除该文件吗? " + this.fileName)) {
                return this.dom.parentNode.removeChild(this.dom)
        }
    }
}
// 工厂进行Upload对象的实例化 并保证相同类型的对象只存在一个
const UploadFactory = (function () {
    const createFlyWeightObjs = {}
    return {
        create(uploadType) {
            return createFlyWeightObjs[uploadType]
                    ? createFlyWeightObjs[uploadType]
                    : (createFlyWeightObjs[uploadType] = new Upload(uploadType))
            }
                }
    })()
// 管理器封装外部状态
    const uploadManager = (function () {
        const uploadDatabase = {}
        return {
            add(id, uploadType, fileName, fileSize) {
                    const flyWeightObj = UploadFactory.create(uploadType)
                    const dom = document.createElement("div")
                    dom.innerHTML =
                            "<span>文件名称:" +
                            fileName +
                            ", 文件大小: " +
                            fileSize +
                            "</span>" +
                            '<button class="delFile">删除</button>'
                    dom.querySelector(".delFile").onclick = function () {
                            flyWeightObj.delFile(id)
                    }
                    document.body.appendChild(dom)
                    uploadDatabase[id] = {
                            fileName: fileName,
                            fileSize: fileSize,
                            dom: dom
                    }
                    return flyWeightObj
            },
            setExternalState(id, flyWeightObj) {
                    const uploadData = uploadDatabase[id]
                    for (var key in uploadData) {
                            flyWeightObj[key] = uploadData[key]
                    }
            }
        }
    })()
//赋予每个文件唯一的id
let id = 0
window.startUpload = function (uploadType, files) {
    for (let i = 0, file; (file = files[i++]); ) {
        var uploadObj = uploadManager.add(id++, uploadType, file.fileName, file.fileSize)
    }
}
//测试调用
startUpload("plugin", [
    {
        fileName: "1.txt",
        fileSize: 1000
    },
    {
        fileName: "2.html",
        fileSize: 3000
    },
    {
        fileName: "3.txt",
        fileSize: 5000
    }
])
startUpload("flash", [
    {
        fileName: "4.txt",
        fileSize: 1000
    },
    {
        fileName: "5.html",
        fileSize: 3000
    },
    {
        fileName: "6.txt",
        fileSize: 5000
    }
])