TypeScript設計模式之中介者、觀察者

AndrewBeamo 7年前發布 | 17K 次閱讀 設計模式 TypeScript

看看用TypeScript怎樣實現常見的設計模式,順便復習一下。

學模式最重要的不是記UML,而是知道什么模式可以解決什么樣的問題,在做項目時碰到問題可以想到用哪個模式可以解決,UML忘了可以查,思想記住就好。

這里盡量用原創的,實際中能碰到的例子來說明模式的特點和用處。

中介者模式 Mediator

特點:為減少對象間的互相引用而引入的一個中介對象,用來來封裝一系列對象的互相操作。

用處:當多個對象間需要互相引用且互相頻繁操作時可以考慮中介者模式,如MVC里的Controller。

注意:中介者本身的復雜度。

下面用TypeScript簡單實現一下中介模式:

現在滴滴打車其實就可以算是中介,就以這個例子吧,對象主要就是用戶,車主和平臺。

先定義用戶, 車主和中介者接口:

用戶的行為是叫車,車主是接送,中介者則需要維護用戶和車主列表并且知道車的狀態和提供叫車服務。

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);
}

接口定義好了就可以寫實現了:

用戶的實現,持有中介者的引用,用來注冊,叫車和付款,本來是沒必要存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('付款');
    }
}

車主的實現,同樣需要持有中介者引用來領任務和報狀態

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);
    }
}

中介的實現,中介的作用就是提供車子服務,這里為了簡單沒維護用戶與車子的關系

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(`車子狀態:${car.isWorking ? '工作' : '閑置'}`);
    }
}

跑一下看看:

let didi = new DiDi();
let taxi = new Taxi(didi);
let user = new User(didi);
user.getTaxi();
user.pay();

//結果
有人叫車
車子狀態:工作
車來了
送完這趟了
車子狀態:閑置
付款

這樣,用戶的目的只是叫車,對中介說聲,中介派出車,用戶不管是什么車,哪來的,把我送到目的地就可以了。

這就是中介者模式的作用,邏輯都在自己這里,用戶不需要管車,車子也不用管用戶,一個叫車,一個接單,互不干擾,突然想到了拉皮條。。。

當然也是因為這里聚集了各方面的邏輯,所以要注意中介者本身的復雜度,中介者本身也需要良好的設計和模式來提高代碼的可讀性和可維護性。

觀察者模式 Observer

特點:定義了對象間的一對多關系,當對象狀態改變時,其他訂閱了這個對象的對象就會收到通知。

用處:當一個對象狀態的改變時需要其他對象也做出響應時可以考慮觀察者模式,如網絡聊天里的群。

注意:與中介者的區別。

下面用TypeScript簡單實現一下觀察者模式:

就以上面說的群聊天為例,群里的每個人都是注冊到群里的對象,任何一個人發了信息其他人都能收到。

先定義群和群用戶的接口:

群需要知道有哪些用戶注冊進來了,并且在有人發消息時去通知所有注冊的人。

用戶則需要發送消息和接收消息。

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);
}

實現用戶和群,用戶在發消息時需要往群里發,群收到消息后通知所有注冊的人

class User implements Observer{
    constructor(public name: string, private subject: Subject){
        this.subject.register(this);
    }

    sendMsg(msg: string){
        console.log(`${this.name} 發送 ${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}發信息:${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!');
//結果:
jim 發送 hello
群收到jim發信息:hello,通知所有人
jim 收到來自jim的消息: hello 
brook 收到來自jim的消息: hello 
lucy 收到來自jim的消息: hello 

lucy 發送 well done!
群收到lucy發信息:well done!,通知所有人
jim 收到來自lucy的消息: well done! 
brook 收到來自lucy的消息: well done! 
lucy 收到來自lucy的消息: well done!

只有要人發消息,所有注冊的人都會收到,跟廣播一樣。

其實觀察者模式可以做得更通用,類似一個消息中心,所有注冊的對象按照一定協議實現匹配事件的方法來獲取通知,消息中心不需要知道是什么類型的對象注冊了,只要實現這個方法,那相關事件有通知時這個方法就會被調到,這樣基本沒有耦合度,有興趣的朋友可以參考我之前寫的一個win10開源庫: LLQNotify ,就是用這種方式實現的。

另外,與中介者模式的區別在于:雖然都是注冊回復,但觀察者是分發性的,注冊的人都能收到,而且中介者則是單一的,使用者發個請求,中介者回一個,使用者不需要知道到底是誰回的,中介隱藏了對象之間的交互。

 

來自:http://www.cnblogs.com/brookshi/p/6545238.html

 

 本文由用戶 AndrewBeamo 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!