最近在學(xué)習(xí)js的設(shè)計(jì)模式,寫了個(gè)demo.
訂閱發(fā)布模式如果按數(shù)學(xué)翻譯其實(shí)就是.一對(duì)多的映射關(guān)系.怎么解釋呢哄尔? 就是一個(gè)開關(guān)姻檀,同時(shí)并聯(lián)幾個(gè)燈泡(在不同房間),觸發(fā)的時(shí)候油湖,幾個(gè)燈泡都會(huì)得到指令为障,然后執(zhí)行發(fā)光的行為。
- 觀察者模式中痢站,目標(biāo)對(duì)象負(fù)責(zé)維護(hù)觀察者。發(fā)布/訂閱模式中發(fā)布者不關(guān)心訂閱者铅搓,只負(fù)責(zé)把消息丟出去就不管了瑟押。
- 觀察者模式中,觀察者要提供一個(gè)接口星掰,然后當(dāng)目標(biāo)對(duì)象發(fā)生改變時(shí)調(diào)用此接口使自身狀態(tài)和目標(biāo)狀態(tài)保持一致多望。即所有的觀察者都要有一個(gè)統(tǒng)一的接口(比如上文中寫的update方法,大家的方法都要叫這個(gè)名字)氢烘。而發(fā)布/訂閱模式中怀偷,訂閱者事件的觸發(fā)不是依靠這樣一個(gè)接口,而是訂閱者通過監(jiān)聽一個(gè)特定的消息(這個(gè)消息一般包含名稱和訂閱者所需要的參數(shù))來觸發(fā)的播玖∽倒ぃ可以理解為訂閱者監(jiān)聽的不是發(fā)布者,而是消息池蜀踏,只要消息池里有它關(guān)心的消息维蒙,即觸發(fā)事件,不管這個(gè)消息是誰發(fā)布過去的果覆。發(fā)布者和訂閱者是解耦的颅痊。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<style type="text/css">
ul {
list-style: none;
}
li {
width: 150px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
background: orangered;
}
li:nth-child(2n-1){
background: orange;
}
</style>
<body>
<span>最新發(fā)布消息</span> 消息:<span id="msg_num">0</span>
<ul id="msg">
</ul>
<textarea name="" rows="" cols="" id="user_input"></textarea>
<button id="user_submit">提交</button>
</body>
<script src="pubsub.js" type="text/javascript" charset="utf-8"></script>
<script src="demo01.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
//測試
Observer.regist('test', function(e) {
console.log(e.type, e.args.msg);
});
Observer.fire('test', {
msg: 'just for test'
});
</script>
</html>
//外觀模式 簡化獲取元素
function $(id) {
return document.getElementById(id);
}
//追加消息
(function() {
function addMsgItem(e) {
var text = e.args.text,
ul = $('msg'),
li = document.createElement('li'),
span = document.createElement('span');
li.innerHTML = text;
span.innerHTML = '×',
span.style.cursor = 'pointer';
//關(guān)閉按鈕
span.onclick = function() {
ul.removeChild(li);
//發(fā)布刪除留言消息
Observer.fire('removeCommentMessage', {
num: -1
});
}
//添加刪除按鈕
li.appendChild(span);
//添加留言節(jié)點(diǎn)
ul.appendChild(li);
}
//注冊(cè)添加留言信息
Observer.regist('addCommentMessage', addMsgItem);
})();
//數(shù)量
(function() {
//更改用戶信息數(shù)目
function changeMsgNum(e) {
//獲取數(shù)目
var num = e.args.num;
$('msg_num').innerHTML = parseInt($('msg_num').innerHTML) + num;
}
//注冊(cè)
Observer.regist('addCommentMessage', changeMsgNum)
Observer.regist('removeCommentMessage', changeMsgNum)
})();
//提交消息
(function() {
//提交信息
$('user_submit').onclick = function() {
var text = $('user_input');
if(text.value === '') {
return;
}
//發(fā)布一條消息
Observer.fire('addCommentMessage', {
text: text.value,
num: 1
});
text.value = '';
}
})();
//觀察者模式
var Observer = (function() {
var _message = {};
return {
//注冊(cè)信息接口
regist: function(type, fn) {
//如果消息不存在,則創(chuàng)建一個(gè)該消息類型
if(typeof _message[type] === 'undefined') {
_message[type] = [fn];
} else {
_message[type].push(fn);
}
},
//發(fā)布信息接口
fire: function(type, args) {
//如果該消息沒有被注冊(cè)局待,返回
if(!_message[type]) {
return;
}
//定義消息信息
var events = {
type: type,
args: args || {}
},
i = 0,
len = _message[type].length;
for(; i < len; i++) {
//依次執(zhí)行注冊(cè)的消息對(duì)應(yīng)的動(dòng)作序列
_message[type][i].call(this, events);
}
},
//移除信息接口
remove: function(type, fn) {
//如果消息動(dòng)作隊(duì)列存在
if(_message[type] instanceof Array) {
//從最后一個(gè)消息動(dòng)作遍歷
var i = _message[type].length - 1;
for(; i >= 0; i--) {
//如果村咋該動(dòng)作則在消息序列中移除相應(yīng)動(dòng)作
_message[type][i] === fn && _message[type].splice(i, 1);
}
}
}
}
})();