http://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailmvp
感覺二者非常像,都是pub/sub機制,如何進行區分?分別在什么不同的場景中進行應用?
- 在Obsever模式中, 不存在封裝約束的單一對象。Observer 和 Subject 必須合作才能維持約束。
- Communication(通訊)模式由觀察者和目標互聯的方式決定:單一目標通常有很多觀察者,有時一個目標的觀察者是另一個觀察者的目標
- Mediator 和 Observer 都能促進松耦合,然后Mediator 模式通過限制對象嚴格通過Mediator 進行通信來實現這個個目的
- Observer 模式創建觀察者對喜愛那個,觀察者對象向訂閱它們的對喜愛那個發布其感興趣的事件。
在GoF的原文中是這樣描述觀察者模式的:
- One or more observers are interested in the state of a subject and register their interest with the subject by attaching themselves. When something changes in our subject that the observer may be interested in, a notify message is sent which calls the update method in each observer. When the observer is no longer interested in the subject's state, they can simply detach themselves.
- 具體應用場景是,當subject的某個動作需要引發一系列不同對象的動作(比如你是一個班長要去通知班里的某些人),與其一個一個的手動調用觸發的方法(私下里一個一個通知),不如維護一個列表(建一個群),這個列表存有你想要調用的對象方法(想要通知的人);之后每次做的觸發的時候只要輪詢這個列表就好了(群發),而不用關心這個列表里有誰,只用關心想讓誰加入讓誰退出
這個列表就叫做ObserverList,它有一些維護列表方法:
function ObserverList(){ this.observerList = []; } ObserverList.prototype.Add = function( obj ){}; ObserverList.prototype.Empty = function(){}; ObserverList.prototype.Count = function(){}; ObserverList.prototype.Get = function( index ){}; ObserverList.prototype.Insert = function( obj, index ){}; ObserverList.prototype.IndexOf = function( obj, startIndex ){}; ObserverList.prototype.RemoveAt = function( index ){};
而我們的subject只用關心兩件事:1.維護這個列表,2.發布事件
function Subject(){ this.observers = new ObserverList(); } Subject.prototype.AddObserver = function( observer ){ this.observers.Add( observer ); }; Subject.prototype.RemoveObserver = function( observer ){ this.observers.RemoveAt( this.observers.IndexOf( observer, 0 ) ); }; Subject.prototype.Notify = function( context ){ var observerCount = this.observers.Count(); for(var i=0; i < observerCount; i++){ this.observers.Get(i).Update( context ); // 在這里假設的是列表里的每個對象都有update方法,但個人覺得這個列表里也可以是不同對象的不同方法,只要能接受當前上下文作為參數, 可以這樣執行: // subscription.callback.apply( subscription.context, args ); } };
中介模式(Mediator Pattern)
讓我們假設這樣一個場景: 有一個Manager一聲令下,需要讓工人A和工人B開工,代碼可以是這樣的
Manager.start = function () { A.work(); B.work(); }
其實還可以這么寫,新增一個中介模塊,這個模塊有存儲了Manager的常用命令比如start,stop,resume,每一個命令其實維護的也是一個列表,比如start的列表下存儲了所有員工的start方法:
Mediator["start"] = [ { name: 'A', callback: 'work' }, { name: 'B', callback: 'workAgain' }, ]
所以Manager的方法可以重寫為
Manager.start = function () { Mediator.publish('start') // publish 為觸發命令函數,以此來觸發start命令下維護的所有回調函數 }
代碼細節就不展示了,主要體現這么一個機制,而如果某個員工要提交自己的work方法供老板調用的話,只要注冊一下就好了
Mediator.subscribe('C', function callback() {});
問題是新增加一個中介模塊的好處是什么?
1.低耦合!如果不是經理要讓員工開始工作,是董事長怎么辦,或者是部門主管怎么辦,難道都要這么寫
XXX.start = function () { A.work() B.work(); }
都要把A.work什么抄一遍?當然不是,只要給中介模塊發出命令就好了,
2.模塊之間不需要進行通信,只要負責廣播和監聽事件就好了
3.在模塊化的javascript中,中介模塊能提高可維護性:是否啟動某個模塊,有沒有權限啟動某個模塊,異步加載某些模塊,模塊之間的依賴關系,某些模塊啟動失敗了怎么辦。這些邊界條件都可以交給它來判斷,而其他模塊只關心實現自己邏輯就好了
最后打個比方,中介模塊真的就像房屋中介一樣!如果你是房東,你只需要下令一聲“我要找人租房”,他們就自然會生成那個列表,你不用直接和房客打交道。