標簽:JS 設(shè)計模式
讀書筆記鏈接:
- 《JS設(shè)計模式》讀書筆記(一)
- 《JS設(shè)計模式》讀書筆記(二)
- 《JS設(shè)計模式》讀書筆記(三)
- 《JS設(shè)計模式》讀書筆記(四)
- 《JS設(shè)計模式》讀書筆記(五)
- 《JS設(shè)計模式》讀書筆記(七-完結(jié))
享元模式
通過劃分內(nèi)部狀態(tài)與外部狀態(tài)來減少需要創(chuàng)建對象的數(shù)量,共享對象。與其他模式不一樣的是,享元模式針對的是性能問題
區(qū)分內(nèi)部狀態(tài)與外部狀態(tài)是使用享元模式的關(guān)鍵:
- 內(nèi)部狀態(tài)通常是可以被共享的屬性,例如性別,歲數(shù),等級之類可以劃分出少數(shù)幾個類別的屬性。
- 外部狀態(tài)就是各不相同的屬性,例如大小,面積之類有很多個取值的屬性。
- 其實內(nèi)外狀態(tài)的區(qū)分關(guān)鍵就是看該屬性的取值哪個少。選最少哪個作為內(nèi)部,其他外部。這樣就使得共享的對象變到最少。
// 抽出內(nèi)部屬性以創(chuàng)建享元,這里內(nèi)部屬性是sex
// 享元模式也可以使用工廠模式來創(chuàng)建每個享元的單例。嚴格限定對象數(shù)量。
var Modal = function(sex) {
this.sex = sex;
}
Modal.prototype.takePhoto = function(index){
console.log('sex='+this.sex + '; cloth=' + this.clothes[index])
}
// 注意通常要用id++來記錄每個享元的外部狀態(tài),這里是clothes
Modal.prototype.wear = function(clothes) {this.clothes = clothes};
var maleModal = new Modal('male')
maleModal.wear(['red','green','blue'])
var femaleModal = new Modal('female')
maleModal.wear(['dress','skirt','pants'])
// 這里只使用了兩個對象就可以完成任務;其實也可以用cloth來做內(nèi)部屬性,不過有6個值,明顯不如sex的兩個值
for(var i=0,l=3;i<l;i++){
maleModal.takePhoto(i);
femaleModal.takePhoto(i);
}
另外與一種享元模式有異曲同工之妙的技術(shù)是對象池技術(shù),原理是使用緩存記錄使用過的對象,調(diào)用時優(yōu)先從緩存調(diào)用,調(diào)用后就放回緩存。
// objpool
var objectPoolFactory = function(createFn) {
var pool = [];
return {
create: function(){
return obj = pool.length === 0 ? createFn.apply(this, arguments) : pool.shift();
},
recover: function(obj) {
pool.push(obj)
}
}
}
// example
var iframeFactory = objectPoolFactory(function(){
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.onload = function(){
iframe.onload = null; // 防iframe重復加載
iframeFactory.recover(iframe);
}
return iframe;
})
var iframe1 = iframeFactory.create();
iframe1.src = 'http://www.baidu.com';
setTimeout(function(){
var iframe2 = iframeFactory.create(); // iframe1 === iframe2
iframe2.src = 'http://www.qq.com'
}, 5000)
狀態(tài)模式
使用狀態(tài)機時,對每一個狀態(tài)都獨立封裝成類(對象),各狀態(tài)類復寫同一個抽象方法,使用該方法來執(zhí)行狀態(tài)機。
不變:狀態(tài)總要變化;狀態(tài)的變換都是通過同一個方法;狀態(tài)有各自的行為;
變化:狀態(tài)類的細節(jié);
結(jié)果:消除switch語句,不修改原有代碼的情況下新增狀態(tài)
// 狀態(tài)模式結(jié)合有限狀態(tài)機,開燈例子
var Light = function() {
// 初始狀態(tài)
// 使用FSM來記錄狀態(tài)對象
this.currState = FSM.off;
this.button = null;
}
Light.prototype.init = function(){
this.button = document.createElement('button');
this.button.innerHTML = 'off';
document.body.append(this.button);
that = this;
this.button.onclick = function(){
that.currState.toggle.call(that);
}
}
// 每個狀態(tài)都是一個對象,包含自己要維護的屬性與一個約定公開的API(這里是toggle)
var FSM = {
off: {
toggle: function(){
console.log('turn off light')
this.currState = FSM.on; // 這里是關(guān)鍵,改變當前狀態(tài)
}
},
on: {
toggle: function(){
console.log('turn on light')
this.currState = FSM.off; // 這里是關(guān)鍵,改變當前狀態(tài)
}
}
}
var light = new Light();
light.init();