Skip to content

Commit 9b1be92

Browse files
committed
享元模式和对象池
1 parent b8da51a commit 9b1be92

File tree

1 file changed

+264
-0
lines changed

1 file changed

+264
-0
lines changed

twelve-chapter/index.js

+264
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
//享元(flyweight)模式是一种用于性能优化的模式,
2+
//多个模特穿多种内衣拍照
3+
4+
5+
6+
//内部状态和外部状态
7+
// 享元模式的目标是尽量减少共享对象的数量,
8+
// 关于如何划分内 部状态和外部状态,
9+
// 下面的几条经验提供了一些指引
10+
/*
11+
 内部状态存储于对象内部。
12+
 内部状态可以被一些对象共享。
13+
 内部状态独立于具体的场景,通常不会改变。
14+
 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享
15+
*/
16+
17+
// 只有当某种共享对象被真正需要时,它才从工厂 中被创建出来。
18+
//可以用一个管理器来记录对象相关的外部状态,使这些外部状 态通过某个钩子和共享对象联系起来
19+
20+
//文件说上传
21+
var id = 0;
22+
window.startUpload = function (uploadTypes,files) {
23+
for(var i=0,file;file=files[i++];){
24+
var uploadObj = new upload(uploadType,file.fileName,file.fileSize);
25+
uploadObj.init(id++);
26+
}
27+
}
28+
29+
var Upload = function(uploadObj,fileName,fileSize){
30+
this.uploadObj = uploadObj
31+
this.fileName = fileName
32+
this.fileSize = fileSize
33+
this.dom = null
34+
}
35+
36+
Upload.prototype.init = function(id){
37+
var that = this;
38+
this.id = id;
39+
this.dom = document.createElement('div')
40+
this.dom.innerHTML =
41+
'<span>文件名称:'+ this.fileName +', 文件大小: '+ this.fileSize +'</span>' + '<button class="delFile">删除</button>';
42+
this.dom.querySelector('.delFile').onclick = function(){
43+
this.delFile();
44+
}
45+
document.body.appendChild(this.dom)
46+
}
47+
48+
Upload.prototype.delFile = function(){
49+
if(this.fileSize < 3000){
50+
return this.dom.parentNode.removeChild(this.dom)
51+
}
52+
53+
if(window.confirm('确定要删除该文件吗? '+ this.fileName)){
54+
return this.dom.parentNode.removeChild(this.dom)
55+
}
56+
}
57+
58+
startUpload( 'plugin', [ {
59+
fileName: '1.txt',
60+
fileSize: 1000
61+
},
62+
{
63+
fileName: '2.html', fileSize: 3000
64+
65+
}, 6
66+
{
67+
fileName: '3.txt',
68+
fileSize: 5000
69+
}
70+
]);
71+
72+
startUpload( 'flash', [ {
73+
fileName: '4.txt',
74+
fileSize: 1000
75+
},
76+
{
77+
fileName: '5.html',
78+
fileSize: 3000
79+
},
80+
{
81+
fileName: '6.txt',
82+
fileSize: 5000
83+
}
84+
]);
85+
86+
87+
/*享元模式重写*/
88+
//剥离外部状态
89+
var Upload = function(uploadType){
90+
this.uploadObj = uploadTypes;
91+
}
92+
93+
Upload.prototype.delFile = function(id){
94+
uploadManger.setExternalState(id,this); //把当前 id 对应的对象的外部状态都组装到共享对象中
95+
96+
if(this.fileSize < 3000){
97+
return this.dom.parentNode.removeChild(this.dom)
98+
}
99+
100+
if(window.confirm('确定要删除该文件吗? '+ this.fileName)){
101+
return this.dom.parentNode.removeChild(this.dom)
102+
}
103+
}
104+
105+
//工厂实例化
106+
var UploadFactory = (function(){
107+
var createdFlyWeightObjs = {};
108+
109+
return {
110+
create:function(uploadType){
111+
if(createdFlyWeightObjs[uploadType]){
112+
return createdFlyWeightObjs[uploadTypes]
113+
}
114+
115+
return createdFlyWeightObjs[uploadType] = new UploadFactory(uploadType)
116+
}
117+
}
118+
})()
119+
120+
//管理器封装外部状态
121+
var uploadManager = (function(){
122+
var uploadDatabase = {};
123+
124+
return {
125+
add:function(id,uploadType,fileName,fileSize){
126+
var flyweightObj = UploadFactory.create(uploadType)
127+
128+
var dom = document.createElement('div')
129+
this.dom.innerHTML =
130+
'<span>文件名称:'+ this.fileName +', 文件大小: '+ this.fileSize +'</span>' + '<button class="delFile">删除</button>';
131+
dom.querySelector('.delFile').onclick = function(){
132+
flyweightObj.delFile(id);
133+
}
134+
135+
document.body.appendChild(dom);
136+
137+
uploadDatabase[id] = {
138+
fileName:fileName,
139+
fileSize:fileSize,
140+
dom:dom,
141+
}
142+
return flyweightObj;
143+
},
144+
setExternalState:function(id,flyweightObj){
145+
var uploadData = uploadDatabase[id];
146+
for(var i in uploadData){
147+
flyweightObj[i] = uploadData[i];
148+
}
149+
}
150+
151+
}
152+
})()
153+
154+
// 是开始触发上传动作的 startUpload 函数
155+
var id = 0;
156+
window.startUpload = function(uploadType,files){
157+
for(var i = 0,file;file= files[i++];){
158+
var uploadObj = uploadManager.add(++id,uploadType,file.fileName,file.fileSize)
159+
}
160+
}
161+
162+
// 创建的 upload 对象数量依然是 2
163+
164+
/*使用场景
165+
 对象的大多数状态都可以变为外部状态。
166+
 一个程序中使用了大量的相似对象。
167+
 由于使用了大量对象,造成很大的内存开销。
168+
 剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象
169+
*/
170+
171+
// 对象池维 护一个装载空闲对象的池子,如果需要对象的时候,不是直接 new,
172+
// 而是转从对象池里获取。如 果对象池里没有空闲对象,则创建一个新的对象,
173+
// 当获取出的对象完成它的职责之后, 再进入 池子等待被下次获取
174+
// 对象池 类比 图书馆
175+
// web 应用 HTTP 连接池 数据库连接池,对象池使用最多的场景大概就是跟 DOM 有关的操作
176+
177+
178+
var toolTipFactory = (function(){
179+
var toolTipPool = [];//对象池
180+
return {
181+
create:function(){
182+
if(toolTipPool.length === 0){ // 如果对象池为空
183+
var div = document.createElement('div') //创建一个dom
184+
document.body.appendChild(div)
185+
return div ;
186+
}else{ // 如果对象池不为空
187+
return toolTipPool.shift();//则从对象池中取出一个dom
188+
}
189+
},
190+
recover:function(toolTipDom){
191+
return toolTipPool.push(toolTipDom) //对象池回收dom
192+
}
193+
}
194+
})()
195+
196+
197+
var array = [];
198+
for(var i=0,str;str = ['A','B'][i++];){
199+
var toolTip = toolTipFactory.create();
200+
toolTip.innerHTML = str;
201+
array.push(toolTip);
202+
}
203+
// a, b dom节点收回对象池
204+
for(var i=0,toolTip;toolTip = array[i++];){
205+
toolTipFactory.recover(toolTip);
206+
}
207+
208+
//在创建6个小气泡
209+
for(var i=0,str;str=['A','B','C','D','E','F'][i++];){
210+
var toolTip = toolTipFactory.create()
211+
toolTip.innerHTML = str;
212+
}
213+
214+
//通用的对象池实现
215+
var objectPoolFactory = function(createObjFn){
216+
var objectPool = [];
217+
218+
return {
219+
create:function(){
220+
var obj = objectPool.length === 0 ?
221+
createObjFn.apply(this,arguments):objectPool.shift();
222+
},
223+
recover:function(obj){
224+
objectPool.push(obj);
225+
}
226+
}
227+
}
228+
229+
var iframeFactory = objectPoolFactory(function(){
230+
var iframe = document.createElement('iframe');
231+
document.body.appendChild(iframe);
232+
iframe.onload = function(){
233+
iframe.onload = null ;//防止 iframe 重复加载的 bug
234+
iframeFactory.recover(iframe);// iframe 加载完成之后回收节点
235+
}
236+
return iframe;
237+
})
238+
239+
var iframe1 = iframeFactory.create(); iframe1.src = 'http:// baidu.com';
240+
var iframe2 = iframeFactory.create(); iframe2.src = 'http:// QQ.com';
241+
setTimeout(function(){
242+
var iframe3 = iframeFactory.create();
243+
iframe3.src = 'http:// 163.com';
244+
}, 3000 );
245+
246+
// 对象池是另外一种性能优化方案,它跟享元模式有一些相似之处,
247+
// 但没有分离内部状态和外 部状态这个过程
248+
249+
250+
//没有内部状态的享元模式
251+
//不需要考虑极速上传与普通上传之间的切换
252+
var Upload = function(){};
253+
var UploadFactory = (function(){
254+
var uploadObj;
255+
return {
256+
create:function(){
257+
if(uploadObj){
258+
return uploadObj;
259+
}
260+
return uploadObj = new Upload();
261+
}
262+
}
263+
})()
264+

0 commit comments

Comments
 (0)