JavaScript设计模式-享元模式
JavaScript设计模式-享元模式
- 概念
- 例子
- 内部状态与外部状态
- 享元模式的通用结构
- 例子
- 总结
- github仓库地址:点击 [设计模式例子](https://github.com/fanhualuoye/design) 查看
概念
享元(flyweight)模式是一种用于性能优化的模式,“fly”在这里是苍蝇的意思,意为蝇量
级。享元模式的核心是运用共享技术来有效支持大量细粒度的对象。如果系统中因为创建了大量类似的对象而导致内存占用过高,享元模式就非常有用了。在
JavaScript 中,浏览器特别是移动端的浏览器分配的内存并不算多,如何节省内存就成了一件非
常有意义的事情。
例子
// 有一家模特儿公司(工厂)const modelFactory = function (type, name) {this.type = typethis.name = name}// 给穿上指定衣服的模特儿拍照,modelFactory.prototype.takePhoto = function () {console.log('给type= ' + this.type + ' name=' + this.name + '拍照')}// 有50件不同的西装,需要拍50张照片for (let i = 1; i <= 50; i++) {// 给每件西装都请一位模特儿,一共请了50个const suitModel = new modelFactory('西装', i)suitModel.takePhoto()}// 有50件不同的羽绒服,需要50张照片for (let j = 1; j <= 50; j++) {// 给每件羽绒服都请一位模特儿,一共请了50个const jacketModel = new modelFactory('羽绒服', j)jacketModel.takePhoto()}// 上面new了100个对象,这样是很占内存(资源),我们可以用享元模式优化//我们只需要两位模特就行了,一个西装模特,一个羽绒服模特const modelFactory = function (type) {this.type = type}modelFactory.prototype.takePhoto = function () {console.log('给type= ' + this.type + ' name=' + this.name + '拍照')}// 分别创建一个西装模特对象和一个羽绒服模特对象:const suitModel = new modelFactory('西装')const jacketModel = new modelFactory('羽绒服')// 给模特依次穿上西装,并进行拍照:for (let i = 1; i <= 50; i++) {suitModel.name = isuitModel.takePhoto()}// 给模特依次穿上羽绒服,并进行拍照:for (let j = 1; j <= 50; j++) {jacketModel.name = jjacketModel.takePhoto()}// 这个西装模特对象和一个羽绒服模特对象就是我们的享元了// 以上就是是享元模式的雏形
内部状态与外部状态
- 享元模式要求将对象的属性划分为内部状态与外部 状态(状态在这里通常指属性)。享元模式的目标是尽量减少共享对象的数量,关于如何划分内 部状态和外部状态,下面的几条经验提供了一些指引。
- 内部状态存储于对象内部。
- 内部状态可以被一些对象共享。
- 内部状态独立于具体的场景,通常不会改变。
- 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享。
这样一来,我们便可以把所有内部状态相同的对象都指定为同一个共享的对象。而外部状态可以从对象身上剥离出来,并储存在外部。
剥离了外部状态的对象成为共享对象,外部状态在必要时被传入共享对象来组装成一个完整的对象。虽然组装外部状态成为一个完整对象的过程需要花费一定的时间,但却可以大大减少系统中的对象数量,相比之下,这点时间或许是微不足道的。因此,享元模式是一种用时间换空间的优化模式。
在上面的例子中,type是内部状态,name是外部状态,通过区分这两种状态,大大减少了系 统中的对象数量。
总结:享元模式共同的属性是内部属性,在创建对象的时候决定;不同的属性是外部属性,在对象创建完后改变。
享元模式的通用结构
- 示例初步展示了享元模式的威力,但这还不是一个完整的享元模式,在这个例子中 还存在以下两个问题。
我们通过构造函数显式new出了两个model对象,在其他系统中,也许并不是一开始就需要所有的共享对象。(不用就不创建)
给 model 对象手动设置了name外部状态,在更复杂的系统中,这不是一个最好的方式,因为外部状态可能会相当复杂,它们与共享对象的联系会变得困难。
- 我们通过一个对象工厂来解决第一个问题,只有当某种共享对象被真正需要时,它才从工厂中被创建出来。对于第二个问题,可以用一个管理器来记录对象相关的外部状态,使这些外部状态通过某个钩子和共享对象联系起来。
例子
// 例子// 工厂进行对象实例化const UploadFactory = (function () {const createdFlyWeightObjs = {}return {create: function (uploadType) {if (createdFlyWeightObjs [uploadType]) {return createdFlyWeightObjs [uploadType]}return createdFlyWeightObjs [uploadType] = new Upload(uploadType)}}})()// 管理器封装外部状态const uploadManager = (function () {// 定义上传文件的集合const uploadDatabase = {}return {// 上传文件处理逻辑add: function (id, uploadType, fileName, fileSize) {// 利用UploadFactory.create工厂进行对象实例化,得到实例,同时,uploadType相同的,只会有一个实例// uploadType就是内部状态了,其他属性就是外部状态了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},// 用来获取当前id的文件对象setExternalState: function (id, flyWeightObj) {const uploadData = uploadDatabase[id]for (const i in uploadData) {flyWeightObj[i] = uploadData[i]}}}})()let id = 0// 开始上传const startUpload = function (uploadType, files) { // uploadType 区分是控件还是 flashfor (let i = 0; i < files.length; i++) {const file = files[i]uploadManager.add(++id, uploadType, file.fileName, file.fileSize)}}// 上传的对象const Upload = function (uploadType) {this.uploadType = uploadType}Upload.prototype.delFile = function (id) {// 这里把id和this传进setExternalState方法,该方法会根据id找到上传的文件对象,并把对象属性赋值给this// 那么下面的this.dom就可以找到相应的文件dom了uploadManager.setExternalState(id, this) // (1)if (this.fileSize < 3000) {return this.dom.parentNode.removeChild(this.dom)}if (window.confirm('确定要删除该文件吗? ' + this.fileName)) {return this.dom.parentNode.removeChild(this.dom)}}// 接下来分别创建 3 个插件上传对象和 3 个 Flash 上传对象: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}])
总结
- 享元模式是为解决性能问题而生的模式,这跟大部分模式的诞生原因都不一样。在一个存在大量相似对象的系统中,享元模式可以很好地解决大量对象带来的性能问题。
- 优缺点:享元模式是一种用时间换空间的优化模式。
github仓库地址:点击 设计模式例子 查看
JavaScript设计模式-享元模式相关推荐
- Python设计模式-享元模式
Python设计模式-享元模式 基于Python3.5.2,代码如下 #coding:utf-8class Coffee:name = ""price = 0def __init_ ...
- 10-Python与设计模式--享元模式
10-Python与设计模式--享元模式 一.网上咖啡选购平台 假设有一个网上咖啡选购平台,客户可以在该平台上下订单订购咖啡,平台会根据用户位置进行线下配送.假设其咖啡对象构造如下: class Co ...
- 设计模式--享元模式实现C++
/********************************* *设计模式--享元模式实现 *C++语言 *Author:WangYong *Blog:http://www.cnblogs.co ...
- 【设计模式】Java设计模式 - 享元模式
[设计模式]Java设计模式 - 享元模式
- Unity设计模式——享元模式(附代码)
Unity设计模式--享元模式(附源码) 享元Flyweight模式是什么 享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的 ...
- 第二十二章 Caché 设计模式 享元模式
文章目录 第二十二章 Caché 设计模式 享元模式 定义 优点 使用场景 结构图 描述 完整示例 实体类 抽象享元角色 实现享元角色 享元工厂 调用 思考 第二十二章 Caché 设计模式 享元模式 ...
- JAVA 设计模式 享元模式
用途 享元模式 (Flyweight) 运用共享技术有效地支持大量细粒度的对象. 享元模式是一种结构型模式. 结构 图-享元模式结构图 Flyweight : 它是所有具体享元类的超类或接口,通过这个 ...
- java设计模式---享元模式
Java深入到一定程度,就不可避免的碰到设计模式这一概念,了解设计模式,将使自己 对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广 泛,遵循一定的编程模式,才能使自己的 ...
- PHP设计模式——享元模式
声明:本系列博客参考资料<大话设计模式>,作者程杰. 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的 ...
最新文章
- 冠军揭晓!京东Alpha开发者大赛Pick谁上了C位
- 学好机器学习必备这12条经验 !(附资料)
- 现代谱估计:多窗口谱相关性
- C# Datagridview完整攻略
- python之路2.0_Python之路【第二十一篇】:JS基础
- LeetCode 1366. 通过投票对团队排名(自定义排序)
- matplotlib scale 刻度
- 一步一步SharePoint 2007之二十二:完美解决实现Form认证后无法再用SharePoint Designer编辑网站的问题...
- 对字符串进行加密解密
- 麦亡9什么时候能装鸿蒙系统,距断供不到10天 麒麟9000即将绝版 华为大招来了:不止鸿蒙2.0...
- java svg to png_如何用Image Magick将SVG转换为PNG?
- Android 的singleTask和singleInstance的一点思考
- 管理者必须要精通的六项管理技能
- 【Arduino】基础传感器使用
- js自执行函数(function(){})()前加个分号是什么意思?
- 罗马帝国开创了辉煌的人类文明,但他们的数字表示法的确有些繁琐,尤其在表示大数的时候,现在看起来简直不能忍受,所以在现代很少使用了。之所以这样,不是因为发明表示法的人的智力的问题,而是因为一个宗教的原因
- 面向需求编程才是常态,聊聊我的经历
- 数据库设计(理论实例)
- 绘画教程:女生伤心眼泪、哭泣表情的画法技巧
- 【深度学习】【积分梯度】深度网络的公理归因(Axiomatic Attribution for Deep Networks)