TypeScript設(shè)計模式之中介者、觀察者的實現(xiàn)
看看用TypeScript怎樣實現(xiàn)常見的設(shè)計模式,順便復(fù)習(xí)一下。
學(xué)模式最重要的不是記UML,而是知道什么模式可以解決什么樣的問題,在做項目時碰到問題可以想到用哪個模式可以解決,UML忘了可以查,思想記住就好。
這里盡量用原創(chuàng)的,實際中能碰到的例子來說明模式的特點和用處。
中介者模式 Mediator
特點:為減少對象間的互相引用而引入的一個中介對象,用來來封裝一系列對象的互相操作。
用處:當(dāng)多個對象間需要互相引用且互相頻繁操作時可以考慮中介者模式,如MVC里的Controller。
注意:中介者本身的復(fù)雜度。
下面用TypeScript簡單實現(xiàn)一下中介模式:
現(xiàn)在滴滴打車其實就可以算是中介,就以這個例子吧,對象主要就是用戶,車主和平臺。
先定義用戶, 車主和中介者接口:
用戶的行為是叫車,車主是接送,中介者則需要維護(hù)用戶和車主列表并且知道車的狀態(tài)和提供叫車服務(wù)。
interface Client{ getTaxi(); pay(); } interface Car{ isWorking: boolean; startWork(); finishWork(); } interface Mediator{ registerClient(client: Client); registerCar(car: Car); getCar(): Car; pay(car: Car); updateCarStatus(car: Car); }
接口定義好了就可以寫實現(xiàn)了:
用戶的實現(xiàn),持有中介者的引用,用來注冊,叫車和付款,本來是沒必要存taxi的,只需要個id就可以了,具體是由中介去做匹配,不過這里為了簡單就直接存對象了
class User implements Client{ taxi: Car; constructor(private mediator: Mediator){ this.mediator.registerClient(this); } getTaxi(){ this.taxi = this.mediator.getCar(); if(this.taxi){ console.log('車來了'); } else { console.log('沒叫到車'); } } pay(){ this.mediator.pay(this.taxi); console.log('付款'); } }
車主的實現(xiàn),同樣需要持有中介者引用來領(lǐng)任務(wù)和報狀態(tài)
class Taxi implements Car{ isWorking: boolean = false; constructor(private mediator: Mediator){ this.mediator.registerCar(this); } startWork(){ console.log('有人叫車'); this.isWorking = true; this.mediator.updateCarStatus(this); } finishWork(){ console.log('送完這趟了'); this.isWorking = false; this.mediator.updateCarStatus(this); } }
中介的實現(xiàn),中介的作用就是提供車子服務(wù),這里為了簡單沒維護(hù)用戶與車子的關(guān)系
class DiDi implements Mediator{ private clientList: Array<Client> = []; private carList: Array<Car> = []; registerClient(client: Client){ this.clientList.push(client); } registerCar(car: Car){ this.carList.push(car); } getCar(): Car{ let car = this.carList.find(o=>!o.isWorking); car.startWork(); return car; } pay(car: Car){ car.finishWork(); } updateCarStatus(car: Car){ console.log(`車子狀態(tài):${car.isWorking ? '工作' : '閑置'}`); } }
跑一下看看:
let didi = new DiDi(); let taxi = new Taxi(didi); let user = new User(didi); user.getTaxi(); user.pay(); //結(jié)果 有人叫車 車子狀態(tài):工作 車來了 送完這趟了 車子狀態(tài):閑置 付款
這樣,用戶的目的只是叫車,對中介說聲,中介派出車,用戶不管是什么車,哪來的,把我送到目的地就可以了。
這就是中介者模式的作用,邏輯都在自己這里,用戶不需要管車,車子也不用管用戶,一個叫車,一個接單,互不干擾。
當(dāng)然也是因為這里聚集了各方面的邏輯,所以要注意中介者本身的復(fù)雜度,中介者本身也需要良好的設(shè)計和模式來提高代碼的可讀性和可維護(hù)性。
觀察者模式 Observer
特點:定義了對象間的一對多關(guān)系,當(dāng)對象狀態(tài)改變時,其他訂閱了這個對象的對象就會收到通知。
用處:當(dāng)一個對象狀態(tài)的改變時需要其他對象也做出響應(yīng)時可以考慮觀察者模式,如網(wǎng)絡(luò)聊天里的群。
注意:與中介者的區(qū)別。
下面用TypeScript簡單實現(xiàn)一下觀察者模式:
就以上面說的群聊天為例,群里的每個人都是注冊到群里的對象,任何一個人發(fā)了信息其他人都能收到。
先定義群和群用戶的接口:
群需要知道有哪些用戶注冊進(jìn)來了,并且在有人發(fā)消息時去通知所有注冊的人。
用戶則需要發(fā)送消息和接收消息。
interface Observer{ name: string; sendMsg(msg: string); receiveMsg(sender: Observer, msg: string); } interface Subject{ register(observer: Observer); unregister(observer: Observer); sendMsg(sender: Observer, msg: string); }
實現(xiàn)用戶和群,用戶在發(fā)消息時需要往群里發(fā),群收到消息后通知所有注冊的人
class User implements Observer{ constructor(public name: string, private subject: Subject){ this.subject.register(this); } sendMsg(msg: string){ console.log(`${this.name} 發(fā)送 ${msg}`); this.subject.sendMsg(this, msg); } receiveMsg(sender: Observer, msg: string){ console.log(`${this.name} 收到來自${sender.name}的消息: ${msg} `); } } class Group implements Subject{ private userList: Array<Observer> = []; register(observer: Observer){ this.userList.push(observer); } unregister(observer: Observer){ var index = this.userList.indexOf(observer); if (index > -1) { this.userList.splice(index, 1); } } sendMsg(sender: Observer, msg: string){ console.log(`群收到${sender.name}發(fā)信息:${msg},通知所有人`); this.notify(sender, msg); } private notify(sender: Observer, msg: string){ this.userList.forEach(user=>user.receiveMsg(sender, msg)); } }
寫段代碼測試一下:
let group = new Group(); let jim = new User1('jim', group); let brook = new User1('brook', group); let lucy = new User1('lucy', group); jim.sendMsg('hello'); lucy.sendMsg('well done!'); //結(jié)果: jim 發(fā)送 hello 群收到j(luò)im發(fā)信息:hello,通知所有人 jim 收到來自jim的消息: hello brook 收到來自jim的消息: hello lucy 收到來自jim的消息: hello lucy 發(fā)送 well done! 群收到lucy發(fā)信息:well done!,通知所有人 jim 收到來自lucy的消息: well done! brook 收到來自lucy的消息: well done! lucy 收到來自lucy的消息: well done!
只有要人發(fā)消息,所有注冊的人都會收到,跟廣播一樣。
其實觀察者模式可以做得更通用,類似一個消息中心,所有注冊的對象按照一定協(xié)議實現(xiàn)匹配事件的方法來獲取通知,消息中心不需要知道是什么類型的對象注冊了,只要實現(xiàn)這個方法,那相關(guān)事件有通知時這個方法就會被調(diào)到,這樣基本沒有耦合度,有興趣的朋友可以參考我之前寫的一個win10開源庫:LLQNotify,就是用這種方式實現(xiàn)的。
另外,與中介者模式的區(qū)別在于:雖然都是注冊回復(fù),但觀察者是分發(fā)性的,注冊的人都能收到,而且中介者則是單一的,使用者發(fā)個請求,中介者回一個,使用者不需要知道到底是誰回的,中介隱藏了對象之間的交互。
到此這篇關(guān)于TypeScript設(shè)計模式之中介者、觀察者的實現(xiàn)的文章就介紹到這了,更多相關(guān)TypeScript中介者、觀察者內(nèi)容請搜索腳本之家以前的文章或繼續(xù)
相關(guān)文章
javascript實現(xiàn)的柱狀統(tǒng)計圖表
下面是完成后的預(yù)覽圖,可以看到,繪制一個表格,耗時0.005毫秒,也就是200分之一秒。效率我還是比較滿意的!2010-07-07js貪吃蛇網(wǎng)頁版游戲特效代碼分享(挑戰(zhàn)十關(guān))
這篇文章主要為大家詳細(xì)介紹了js貪吃蛇網(wǎng)頁版游戲特效,游戲總共有十關(guān),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2015-08-08Js判斷參數(shù)(String,Array,Object)是否為undefined或者值為空
在一些前端控件要提交數(shù)據(jù)到服務(wù)器端的數(shù)據(jù)驗證過程中,需要判斷提交的數(shù)據(jù)是否為空。如果是普通表單的字符串?dāng)?shù)據(jù),只需要在 trim 后判斷 length 即可,而這里需要的數(shù)據(jù)可以是各種不同的類型,通過 JSON.stringify(data) 進(jìn)行序列化后再傳遞2013-11-11uniapp微信小程序無法使用本地靜態(tài)資源圖片(背景圖在真機不顯示)的解決方法
寫微信小程序的時候,難免會為了趕進(jìn)度而直接使用本地的圖片,在模擬器上的時候可以正確顯示圖片,但是到手機上就無法顯示圖片了,下面這篇文章主要給大家介紹了關(guān)于uniapp微信小程序無法使用本地靜態(tài)資源圖片(背景圖在真機不顯示)的方法,需要的朋友可以參考下2022-12-12