發(fā)布-訂閱模式饲帅,又稱觀察者模式矛绘。
一對(duì)多:當(dāng)一個(gè)對(duì)象更新時(shí)虑鼎,所有依賴它的對(duì)象都將得到通知并自動(dòng)更新辱匿。
關(guān)鍵代碼:在抽象類(lèi)里有一個(gè) array list 來(lái)存放觀察者們。
關(guān)鍵概念:即使沒(méi)有觀察者炫彩,主體也可以獨(dú)自存在并正常運(yùn)行匾七。
主體“發(fā)布”事件。
觀察者通過(guò)“訂閱”事件來(lái)觀察對(duì)象江兢。
優(yōu)點(diǎn):
有助于解耦昨忆,保持功能的隔絕。
因?yàn)橛|發(fā)事件的代碼和監(jiān)聽(tīng)事件的代碼是完全分離的划址。
缺點(diǎn):
- 如果觀察者和主體之間有循環(huán)依賴扔嵌,系統(tǒng)會(huì)循環(huán)崩潰。
- 主體有很多直接/間接觀察者的話夺颤,通知到所有觀察者很花時(shí)間痢缎。
- 觀察者們不知道主體怎么發(fā)生變化,只知道它變了世澜。
代碼1 - 紅寶書(shū)版:
function EventTarget() {
this.handler = {}
}
EventTarget.prototype = {
constructor: EventTarget,
addHander(type, handler) {
//增加事件
if (typeof this.handler[type] == 'undefined') {
this.handler[type] = []
}
this.handler[type].push(handler) //可能有很多方法独旷,把方法做為數(shù)組
},
fire(event) {
//觸發(fā)事件,傳入觸發(fā)的事件名和參數(shù)
if (!event.target) {
//如果沒(méi)有傳入事件對(duì)象寥裂,把實(shí)例做為對(duì)象
event.target = this
}
//事件方法做為數(shù)組存在
const handlers = this.handler[event.type]
//if (handlers instanceof Array) {
if (Array.isArray(handlers)) {
const length = handlers.length
for (let k = 0; k < length; k++) {
handlers[k](event)
}
}
},
removeHander(type, handler) {
//刪除事件
const handlers = this.handler[type]
//if (handlers instanceof Array) {
if (Array.isArray(handlers)) {
const length = handlers.length
for (let k = 0; k < length; k++) {
if (handlers[k] == handler) {
this.handler[type].splice(k, 1)
break
}
}
}
}
}
let event = new EventTarget()
function hello() {
console.log('hi')
}
event.addHander('click', hello)
event.fire({
type: 'click'
})
代碼2 - es6版:
// to do
調(diào)用代碼:
function handleMessage(event){
alert("Message received: " + event.message);
}
var target = new EventTarget();
target.addHandler("message", handleMessage);
target.fire({ type: "message", message: "Hello world!"});
target.removeHandler("message", handleMessage);
target.fire({ type: "message", message: "Hello world!"});
結(jié)合“寄生組合式繼承”(紅寶書(shū)p172):
function Person(name, age){
EventTarget.call(this);
this.name = name;
this.age = age;
}
inheritPrototype(Person,EventTarget);
Person.prototype.say = function(message){
this.fire({type: "message", message: message});
};
function handleMessage(event){
alert(event.target.name + " says: " + event.message);
}
var person = new Person("Nicholas", 29);
person.addHandler("message", handleMessage);
person.say("Hi there.");
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //create object
prototype.constructor = subType; //augment object
subType.prototype = prototype; //assign object
}
參考資料:
- 《紅寶書(shū)》第22章 高級(jí)技巧 - 自定義事件 p616 - 618
- 菜鳥(niǎo)教程 https://www.runoob.com/design-pattern/observer-pattern.html
- 霧切's blog 自定義事件/觀察者模式