俗話說,一個模式三個坑。 中介者模式應該算最坑的一個模式,坑不在於他的原理。而在於他的名字和其餘模式的使用,真尼瑪像。首先,「中介者「 好像是一切模式裏面都有的一個東西,好比,享元模式中-元對象,訂閱發佈模式中-全局監聽Event... 可是,這個模式恰恰又叫作中介者模式(哎,曾經說模式的時候,感受什麼都是中介者模式)。html
因此,這裏咱們首先要攻克的難關就是,中介者模式的features。安全
首先,咱們須要回憶一下使用訂閱發佈模式中,是怎樣一個場景app
恩,中間須要有一個鏈接節點,即,發佈者只須要和鏈接者有關聯,而訂閱者一樣也只須要和鏈接者有關聯。 因此,這個點就是中介者模式最獨特的feature. 下圖能夠清楚的看出,中介者模式的特色。函數
知道了吧,中介者模式最突出的就是,由中介者來掌管一切,比訂閱者中的鏈接節點的地位好像就是爸爸和兒子的關係。工具
在發佈訂閱模式中有着全局對象Event的管理,那中介者模式中的boss應該怎樣表達呢?學習
首先,咱們須要說明一下,中介者模式主要的應用場景是什麼。this
有大量相互關聯的對象spa
每一個對象都能改變狀態.net
你寫的代碼比較爛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~