實用模式之中介者模式

俗話說,一個模式三個坑。 中介者模式應該算最坑的一個模式,坑不在於他的原理。而在於他的名字和其餘模式的使用,真尼瑪像。首先,「中介者「 好像是一切模式裏面都有的一個東西,好比,享元模式中-元對象,訂閱發佈模式中-全局監聽Event... 可是,這個模式恰恰又叫作中介者模式(哎,曾經說模式的時候,感受什麼都是中介者模式)。html

因此,這裏咱們首先要攻克的難關就是,中介者模式的features。安全

中介者模式

首先,咱們須要回憶一下使用訂閱發佈模式中,是怎樣一個場景app

恩,中間須要有一個鏈接節點,即,發佈者只須要和鏈接者有關聯,而訂閱者一樣也只須要和鏈接者有關聯。 因此,這個點就是中介者模式最獨特的feature. 下圖能夠清楚的看出,中介者模式的特色。函數

知道了吧,中介者模式最突出的就是,由中介者來掌管一切,比訂閱者中的鏈接節點的地位好像就是爸爸和兒子的關係。工具

中介者模式的實現

在發佈訂閱模式中有着全局對象Event的管理,那中介者模式中的boss應該怎樣表達呢?學習

首先,咱們須要說明一下,中介者模式主要的應用場景是什麼。this

  1. 有大量相互關聯的對象spa

  2. 每一個對象都能改變狀態.net

  3. 你寫的代碼比較爛prototype

差很少中介者模式可以解決以上的問題。

徒兒,給師傅去要個栗子來。
好的,師傅!!!

栗子來了:

你們好,(我僞裝我是一名學霸) 同窗們可能常常去的地方,應該就是圖書館了,常常會去圖書管理處借一些書來看,好比: 藏地密碼,阿彌陀佛麼麼噠...等等。咱們憑藉着盡職的圖書館阿姨,每每能夠借到咱們想要的書本。若是已經被借走了,還能夠在阿姨那裏登記,而且若是書還回來的,會通知你過來取。

恩,總結一下:

圖書館阿姨其實就是一箇中介者,咱們找書,都是經過圖書管理處詢問,而後他們負責給咱們查詢。 若是沒有這個管理處的話,就像咱們平時同樣,在羣裏問問,"你們有xxx書嗎?能借我看兩天嗎?"。固然,這樣每每會石沉大海。

咱們用代碼模擬一下:

//咱們先假設圖書管理系統只有借和還的功能
//我的
function Person(name){
    this.name = name;
}
Person.prototype.lend = function(bookName){
    Manager.assign('lend',this,bookName);
}
Person.prototype.back = function(bookName){
    Manager.assign('back',this,bookName);
}
//建立一個工廠模式
var peopleFactory = (function(){
    var people = {};
    return function(name){
        var person = people[name];
        if(person){
            return person;
        }
        person = new Person(name);
        people[name] = person;
        return person;
    }
})();
//中介者,圖書管理處
var Manager = (function(){
    var lendList = {},
        stock = {},
        operations = {};
    operations.lend = function(person,bookName){
        var num = stock[bookName];

        if(num===undefined){  //判斷是否有書
            console.log("圖書館沒有該書");
            return;
        }
        if(num===0){  //書本已經借完
            console.log("該書已經借完");
            return;
        }
        stock[bookName]--;  //將數量減一
        lendList[person.name] = bookName;
        console.log('借閱成功');
    }
    operations.back = function(person,bookName){
        var bookName = lendList[person.name];  //返回借書人借的書名
        if(bookName === null){
            throw "該人,並無借書";
        }
        stock[bookName]++;  //還書
        lendList[person.name] = null;  //將借書人的清空
    }
    operations.addStock = function(){  //初始庫存,addStock({bookName:jimmy,num:2})
        for(var i = 0,book;book = arguments[i++];){
            stock[book.bookName] = book.num;
        }
    }
    var assign = function(){
        var order = Array.prototype.shift.call(arguments);
        operations[order].apply(this,arguments);
    }
    return {
        assign
    }
})();
Manager.assign('addStock',{bookName:"藏地密碼",num:1},{bookName:"阿彌陀佛麼麼噠",num:3});
var xiaoMing = peopleFactory("xiaoMing");
var jimmy = peopleFactory("jimmy");
var hanMM = peopleFactory("hanMM");
xiaoMing.lend("藏地密碼");
jimmy.lend("藏地密碼");
//還書的過程
xiaoMing.back("藏地祕密");
jimmy.lend('藏地密碼');  //終於借成功了

以上是一個簡單的中介者模式的縮影,要始終記着那張圖表明的內涵,中介者模式是不須要在將請求傳遞出去的(或者說,情感上沒有傳遞出去)。

中介者模式的現實意義

上面意淫了一個圖書管理處(實話說,沒有卵用). 咱們來個真的。

徒兒,給師傅找個栗子。
好,師傅!!!

咱們要學習帝吧人民,進能打td,退能刷淘寶。 咱們這裏不說淘寶的事,但說一個電子商務的事。 如今Mooc這麼火,各類線上課程也是numberous。我也上過。 一個線上的課程須要購買,購買的流程基本上就是,選擇你想要的課程,而後,選擇你要上課的人數(你是一個媽媽,你能夠給你兩個孩紙各買一個ID),若是上課人數未滿的話,恭喜,你在家等開課就over了。若是課程滿的話,你要麼等下一期,要麼,直接找另一門課。

若是使用,面向過程的思惟寫的話,我相信這個,不是通常的複雜。

因此,咱們使用面向對象的思惟重構一下。

首先,咱們得拿到課程的數據,好比,課程名,已經報的課程人數,課程價格等。當咱們選擇一個課程的時候,界面上確定須要做出相應的處理,好比,渲染課程價格,剩餘人數。但咱們添加購買人數的時候,若是未超出,則能夠購買,若是超出,則須要將購買的按鈕改成不可選中狀態。

恩,大體過程就是這樣,咱們使用中介者模式想想。

首先,數據須要放在中介者模式內,用戶的一切操做,都會傳遞給中介者模式,由他來選擇是哪個html部分發生改變。

好,咱們用代碼實現如下。

課程購買

上面是整個邏輯和頁面,這裏我主要針對js說明一下。

(function() {
    console.dir($(".courses"))
    bind($(".courses"), function(e) { //課程內容改變時
        mediator.command(e.target);
    }, 'change');
    bind($(".num"), function(e) { //報名人數改變時
        mediator.command(e.target);
    }, 'keyup');

    bind($(".buy"), function(e) { //綁定夠買函數
        mediator.command(e.target);
    }, "click");

    var utils = (function() { //工具函數
        var change = function(ele, val) { //改變內容
            ele.innerHTML = val;
        }
        return {
            change
        };
    })();



    var mediator = (function() { //中介者
        var price = $(".price"), //課程價格
            remainder = $('.remainder'), //剩餘人數
            num = $(".num"), //購買人數
            buyBtn = $('.buy'), //購買btn
            course;
        var changePR = function(courseName) { //改變價格和人數
            course = data[courseName];
            console.log(course);
            utils.change(price, course.price); //改變價格
            utils.change(remainder, course.remainder); //改變人數
        }
        var prohitBtn = (function() { //改變購買btn狀態
            var use = `<button class="shoppingBtn">購買</button>`,
                ban = `<button class="prohit" disabled>人數已滿</button>`,
                status = true;
            return function(flag) {
                if (status === flag) { //若是狀態不變,則不改變內容
                    return;
                }
                if (flag === true) { //能夠購買
                    buyBtn.innerHTML = use;
                    status = true;
                } else { //禁止購買
                    buyBtn.innerHTML = ban;
                    status = false;
                }
            }
        })();
        var detect = function() { //檢測購買輸入的內容
                var number = Number(num.value.trim());
                if (!course) {
                    alert("請先選擇課程");
                    return;
                }
                if (number > course.remainder) {
                    prohitBtn(false); //不可以買
                }  else {
                    prohitBtn(true); //能夠夠買
                }
            }
            //當課程類改變時,觸發改變名額,價格以及根據購買人數改變購買Btn的狀態
        var coursesChange = function(courseName) {
            //改變價格和人數
            changePR(courseName);
            //根據input框的值,改變btn的狀態
            detect();
        }
        var detectBuy = function() {
            var number = Number(num.value.trim());
            if (number === null || number == 0) {
                alert('請先輸入購買數量~');
            } else {
                alert("購買成功");
            }
        }
        var command = function(target) {
            var classList = target.classList;
            if (classList.contains('courses')) {
                console.dir(target.value);
                var val = target.value;
                //執行
                coursesChange(val);
            } else if (classList.contains('num')) {
                var val =target.value.trim(),
                    reg = /\d+/;
                if (!reg.test(val)) {
                    alert("輸入內容只能爲數字");
                    return;
                }
                //執行
                detect();
            } else if(classList.contains("shoppingBtn")){
                detectBuy();
            }
        }
        return {
            command
        }
    })();
})();

能夠從上面的代碼看出,比較清晰的將溝壑關係解除,上面的中介者模式中也會用到代理模式等其餘相關的知識。固然,這段代碼並非特別好,關鍵在於處理的邏輯較多,有大量的if判斷語句,因此也但願讀者,可使用之前所學的js模式進行重構,我相信到時候你的代碼整潔程度必定遠優於鄙人寫的代碼。

淺說中介者模式

其實,中介者模式是我最喜歡使用的模式之一,由於他好寫易上手。可是缺點也是顯而易見的,就是,你會在程序中增長一個巨大的對象,而你的噩夢就是維護這個對象。 中介者裏面會包含大量的邏輯,設計較多的節點獲取,形成的維護難度也是顯而易見的。因此,仍是那句話,不要爲了模式而模式,這個世界上沒有萬能的模式,就和沒有絕對安全的系統同樣。

ending~

相關文章
相關標籤/搜索