GOF設計模式—Smalltalk MVC筆記
MVC通過建立一個“訂購 /通知”協議來分離視圖和模型。視圖必須保證它的顯示正確地反映了模型的狀態。一旦模型的數據發生變化,模型將通知有關的視圖,每個視圖相應地得到刷新自己的機會。這種方法可以讓你為一個模型提供不同的多個視圖表現形式,也能夠為一個模型創建新的視圖而無須重寫模型。
這樣當然能為一個模型提供多個視圖啦,因為模型不屬于某一個具體的視圖,這樣誰都可以去使用它了。個人覺得MVC只適合用在一對多的情況下,一個模型對多個視圖。不然這種分離沒有啥意義,反而使模型和視圖太松散了。
將對象分離,使得一個對象的改變能夠影響另一些對象,而這個對象并不需要知道那些被影響的對象的細節。這個更一般的設計被描述成 Observer模式。
將對象分離就是將視圖、模型、控制器分離,使模型不依賴于視圖和控制器,但這樣的話就會出現一個問題,當模型狀態更新時,如何通知視圖觸發更新?如果直接通過模型通知視圖,那么又會導致依賴性,為了解決這個問題,引入了Observer模式,當模型狀態更新時,由觀察器通知其他對象更新狀態。各個視圖實現Observer接口,并向模型注冊。模型將跟蹤由訂閱更改的所有觀察器組成的列表,當模型發生改變時,模型將會遍歷所有已注冊的觀察器,并將更改通知它們,此方法通常稱為"發布-訂閱"。
代碼1:
<input type="text" id="input">
<script>
// 觀察器
var observer = {
listen:[],
addListen(item){
this.listen.push(item);
},
triggerListen(data){
this.listen.forEach(function(item){
item.upView(data);
});
}
};
// 模型
var model = {
data:"",
upData(data){
this.data = data;
this.triggerListen(this.data);
}
};
model.__proto__ = observer;
// 視圖1
var view = {
upView(data){
console.log("view1:",data);
}
};
// 視圖2
var view2 = {
upView(data){
console.log("view2:",data);
}
};
// 控制器
var controller = {
event(){
document.getElementById("input").addEventListener("input",function(){
model.upData(this.value);
});
}
};
controller.event();
model.addListen(view);
model.addListen(view2);
</script>
模型不直接通知視圖,而是通知觀察器,由觀察器來通知。
之前的做法可能會是下面這樣:
// 模型
var model = {
data:"",
upData(data){
this.data = data;
view.upView(this.data);
view.upView2(this.data);
}
};
// 視圖1
var view = {
upView(data){
console.log("view1:",data);
}
};
// 視圖2
var view2 = {
upView(data){
console.log("view2:",data);
}
};
// 控制器
var controller = {
event(){
document.getElementById("input").addEventListener("input",function(){
model.upData(this.value);
});
}
};
controller.event();
由于模型和視圖直接接觸,導致一旦再添加視圖或刪除,都需要去操作模型內部代碼,如果代碼是自己寫還好,如果交由同事,這種寫法就不是很好了。以上代碼還算好的了,如果將模型和數據混在一起,當新增一個模型時又得重新寫一份模型了。
在這幾段代碼中,我發現控制器的概念就不是那么強烈了,可有可無,因為控制器的作用就是解釋用戶的鼠標和鍵盤輸入,以通知模型或視圖進行相應的更改,而在web瀏覽器中,我們只需要通知模型,而通知模型web瀏覽器提供了事件機制。
在代碼1中,由于模型繼承至觀察器,而某些語言如javascript,它就只支持單繼承,因此這種做法會導致它無法繼承至其他對象,一個可行的解決方案是將觀察器寫在模型中。
<input type="text" id="input">
<script>
// 模型
class Model{
constructor(){
var data = "";
this._listener = [];
this.setData = function(newData){
data = newData;
this.triggerListen(newData);
};
this.getData = function(){
return data;
};
}
addListen(item){
this._listener.push(item);
}
triggerListen(){
var _this = this;
this._listener.forEach(function(item){
item.upView(_this.getData());
});
}
}
// 視圖1
var view = {
upView(data){
console.log("view1:",data);
}
};
// 視圖2
var view2 = {
upView(data){
console.log("view2:",data);
}
};
var model = new Model;
model.addListen(view);
model.addListen(view2);
// 不再使用控制器
document.getElementById("input").addEventListener("input",function(){
model.setData(this.value);
});
</script>
將一些對象劃為一組,并將該組對象當作一個對象來使用。這個設計被描述為C o m p o s i t e 模式,該模式允許你創建一個類層次結構,一些子類定義了原子對象(如B u t t o n)而其他類定義了組合對象( C o m p o s i t e Vi e w ),這些組合對象是由原子對象組合而成的更復雜的對象
從細顆粒到一粒再由粒組合粒成為一個組,由組再組合形成一個對象,如果要使用原子對象,那么得考慮清楚是否有必要,畢竟原子對象太過于原始,要說組合,function就是最好的例子。
一個策略是一個表述算法的對象。當你想靜態或動態地替換一個算法,或你有很多不同的算法,或算法中包含你想封裝的復雜數據結構,這時策略模式是非常有用的。
每個算法都是獨立的,使用的時候傳遞相應的算法。
M V C 的主要關系還是由 O b s e r v e r 、C o m p o s i t e 和S t r a t e g y 三個設計模式給出的。
文章列表