代理模式、中介者模式 代理模式 在面向對象設計中,有一個單一職責原則,指就一個類(對象、函數)而言,應該僅有一個引起它變化的原因。如果一個對象承擔了過多的職責,就意味著它將變得巨大,引起它變化的原因就多,它把這些職責耦合到了一起,這種耦合會導致程式難於維護和重構。 這時候,我們可以把該對象(本體)的 ...
代理模式、中介者模式
代理模式
在面向對象設計中,有一個單一職責原則,指就一個類(對象、函數)而言,應該僅有一個引起它變化的原因。如果一個對象承擔了過多的職責,就意味著它將變得巨大,引起它變化的原因就多,它把這些職責耦合到了一起,這種耦合會導致程式難於維護和重構。
這時候,我們可以把該對象(本體)的其中一部分職責分離出來給一些第三方對象去做,本體只管自己的一些核心職責,這些第三方對象就稱作代理。代理對象可以作為對象(也叫“真正的主體”)的保護者,讓真正的主體對象做儘量少的工作。在代理設計模式中,一個對象充當了另一個對象的介面的角色。
通常代理和本體的介面應該保持一致性,這樣當不需要代理的時候,用戶可直接訪問本體。
當我們不方便直接訪問一個對象時,就可以考慮給該對象招一個代理。
代理可用於:圖片預載入、合併HTTP請求(代理收集一定時間內的所有HTTP請求,然後一次性發給伺服器)、惰性載入(通過代理處理和收集一些基本操作,然後僅在真正需要本體的時候才載入本體)、緩存代理(緩存請求結果、計算結果)等
例子1:圖片預載入
var myImage = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc:function(src){
imgNode.src = src;
}
}
})();
//代理函數
var proxyImage = (function(){
var img = new Image;
img.onload = function(){
myImage.setSrc(this.src);
}
return{
setSrc:function(src){
myImage.setSrc('loading.gif');
img.src = src;
}
}
})();
proxyImage.setSrc('show.jpg');
中介者模式
中介者模式的作用就是解除對象與對象之間的緊耦合關係,它也稱‘調停者’。所有的對象都通過中介者對象來通信,而不是相互引用,所以當一個對象發生改變時,只需要通知中介者即可。
如:機場的指揮塔,每架飛機都只需要和指揮塔通信即可,指揮塔知道每架飛機的飛行狀況,可以安排所有起降時間,調整航線等
中介者模式符合迪米特法則,即最少知識原則,指一個對象應該儘可能少地瞭解另外的對象。如果對象之間的耦合性太高,則改變一個對象,會牽動很多對象,難於維護。當對象耦合很緊時,要修改一個對象而不影響其它的對象是很困難的。
如果對象之間的複雜耦合確實導致調用和維護出現了困難,而且這些耦合度隨項目的變化呈指數增長,那我們就可以考慮用中介者模式來重構代碼!中介者通過解耦來提升代碼的可維護性。
例子1:游戲
玩家對象是通過Player()構造函數來創建的,有自己的points和name屬性。原型上的play()方法負責給自己加一分然後通知中介者:
function Player(name) {
this.points = 0;
this.name = name;
}
Player.prototype.play = function () {
this.points += 1;
mediator.played();
};
scoreboard對象(計分板)有一個update()方法,它會在每次玩家玩完後被中介者調用。計分析根本不知道玩家的任何信息,也不保存分數,它只負責顯示中介者給過來的分數:
var scoreboard = {
element: document.getElementById('results'),
update: function (score) {
var i, msg = '';
for (i in score) {
if (score.hasOwnProperty(i)) {
msg += '<p><strong>' + i + '<\/strong>: ';
msg += score[i];
msg += '<\/p>';
}
}
this.element.innerHTML = msg;
}
};
現在我們來看一下mediator對象(中介者)。在游戲初始化的時候,在setup()方法中創建游戲者,然後放後players屬性以便後續使用。played()方法會被游戲者在每輪玩完後調用,它更新score哈希然表然後將它傳給scoreboard用於顯示。最後一個方法是keypress(),負責處理鍵盤事件,決定是哪位玩家玩的,並且通知它:
var mediator = {
players: {},
setup: function () {
var players = this.players;
players.home = new Player('Home');
players.guest = new Player('Guest');
},
played: function () {
var players = this.players,
score = {
Home: players.home.points,
Guest: players.guest.points
};
scoreboard.update(score);
},
keypress: function (e) {
e = e || window.event; // IE
if (e.which === 49) { // key "1"
mediator.players.home.play();
return;
}
if (e.which === 48) { // key "0"
mediator.players.guest.play();
return;
}
}
};
最後一件事是初始化和結束游戲:
// go!
mediator.setup();
window.onkeypress = mediator.keypress;
// game over in 30 seconds
setTimeout(function () {
window.onkeypress = null;
alert('Game over!');
}, 30000);
例子2:賣手機
var goods = { //庫存
'red|32G':3,
'red|16G':5,
'blue|32G':3,
'blue|16G':6
}
//中介者
var mediator = (function(){
function id(id){
return document.getElementById(id);
}
var colorSelect = id('colorSelect'),
memorySelect = id('memorySelect'),
numberInput = id('numberInput'),
colorInfo = id('colorInfo'),
memoryInfo = id('memoryInfo'),
numberInfo = id('numberInfo'),
nextBtn = id('nextBtn');
return{
changed:function(obj){
var color = colorSelect.value,
memory = memorySelect.value,
number = numberInput.value,
stock = goods[color+'|'+memory];
if(obj === colorSelect){
colorInfo.innerHTML = color;
}else if(obj === memorySelect){
memoryInfo.innerHTML = memory;
}else if(obj === numberInput){
numberInfo.innerHTML = number;
}
if(!color){
nextBtn.disabled = true;
nextBtn.innerHTML = '請選擇手機顏色';
return;
}
if(!memory){
nextBtn.disabled = true;
nextBtn.innerHTML = '請選擇記憶體大小';
return;
}
if(Number.isInteger(number-0) && number > 0){
nextBtn.disabled = true;
nextBtn.innerHTML = '請輸入正確的購買數量';
return;
}
nextBtn.disabled = false;
nextBtn.innerHTML = '放入購物車';
}
}
})();
//添加事件
colorSelect.onchange = function(){
mediator.changed(this);
}
memorySelect.onchange = function(){
mediator.changed(this);
}
numberInput.onchange = function(){
mediator.changed(this);
}
參考文獻: 《JavaScript模式》 《JavaScript設計模式與開發實踐》