天天看點

js設計模式【詳解】—— 中介者模式

目錄

​​中介者模式的定義​​

​​中介者模式和觀察者模式的差別​​

​​中介者模式和外觀模式的差別​​

​​示範範例——中介者模式​​

中介者模式的定義

中介者模式(Mediator):用一個中介對象來封裝一系列的對象互動。中介者使各對象不需要顯式地互相引用,進而使其耦合松散,而且可以獨立地改變它們之間的互動。

類型:行為模式

用途:解除對象與對象之間的緊耦合關系

現實中的中介者模式:機場指揮塔就是中介者,它控制着飛機的起飛和降落,因為所有的溝通都是從飛機向塔台彙報來完成的,而不是飛機之前互相溝通。

使用場景:如果對象之間的複雜耦合确實導緻調用和維護出現了困難,而且這些耦合度随項目的變化呈指數增長曲線,那我們就可以考慮用中介者模式來重構代碼。

優點:中介者模式使各個對象之間得以解耦,以中介者和對象之間的一對多關系取代了對象之間的網狀多對多關系。各個對象隻需關注自身功能的實作,對象之間的互動關系交給了中介者對象來實作和維護。

js設計模式【詳解】—— 中介者模式
js設計模式【詳解】—— 中介者模式

缺點:系統中會新增一個中介者對象,因為對象之間互動的複雜性,轉移成了中介者對象的複雜性,使得中介者對象經常是巨大的。中介者對象自身往往就是一個難以維護的對象。

中介者模式和觀察者模式的差別

  • 觀察者模式(​​javascript:void(0)​​)沒有封裝限制的單個對象,相反,觀察者Observer和具體類Subject是一起配合來維護限制的,溝通是通過多個觀察者和多個具體類來互動的:每個具體類通常包含多個觀察者,而有時候具體類裡的一個觀察者也是另一個觀察者的具體類。
  • 中介者模式所做的不是簡單的分發,而是扮演着維護這些限制的職責。

中介者模式和外觀模式的差別

  • 中介者所做的是在子產品之間進行通信,是多向的
  • 外觀模式(​​javascript:void(0)​​)隻是為某一個子產品或系統定義簡單的接口而不添加額外的功能。系統中的其它子產品和外觀模式這個概念沒有直接聯系,可以認為是單向性。

示範範例——中介者模式

編寫一個手機購買的頁面,在購買流程中,可以選擇手機的顔色、輸入購買數量、選擇手機記憶體,同時頁面中有兩個展示區域,分别向使用者展示剛剛選擇好的顔色和數量。還有一個按鈕動态顯示下一步的操作,我們需要查詢該顔色手機對應的庫存,如果庫存數量少于這次的購買數量,按鈕将被禁用并且顯示庫存不足,反之按鈕可以點選并且顯示放入購物車。

<body>
選擇顔色: <select id="colorSelect">
<option value="">請選擇</option>
<option value="red">紅色</option>
<option value="blue">藍色</option>
</select>
選擇記憶體: <select id="memorySelect">
<option value="">請選擇</option>
<option value="32G">32G</option>
<option value="16G">16G</option>
</select>
輸入購買數量: <input type="text" id="numberInput"/><br/>
您選擇了顔色: <div id="colorInfo"></div><br/>
您選擇了記憶體: <div id="memoryInfo"></div><br/>
您輸入了數量: <div id="numberInfo"></div><br/>
<button id="nextBtn" disabled="true">請選擇手機顔色和購買數量</button>
</body>      
// 手機庫存(從後端擷取得到)
var goods = {
    "red|32G": 3,
    "red|16G": 0,
    "blue|32G": 1,
    "blue|16G": 6
};

// 中介者
var mediator = (function(){
    var colorSelect = document.getElementById( 'colorSelect' ),
    memorySelect = document.getElementById( 'memorySelect' ),
    numberInput = document.getElementById( 'numberInput' ),
    colorInfo = document.getElementById( 'colorInfo' ),
    memoryInfo = document.getElementById( 'memoryInfo' ),
    numberInfo = document.getElementById( 'numberInfo' ),
    nextBtn = document.getElementById( 'nextBtn' );
    return {
        changed: function( obj ){
            var color = colorSelect.value, // 顔色
            memory = memorySelect.value,// 記憶體
            number = numberInput.value, // 數量
            stock = goods[ color + '|' + memory ]; // 顔色和記憶體對應的手機庫存數量
            if ( obj === colorSelect ){ // 如果改變的是選擇顔色下拉框
                colorInfo.innerHTML = color;
            }else if ( obj === memorySelect ){
                memoryInfo.innerHTML = memory;
            }else if ( obj === numberInput ){
                numberInfo.innerHTML = number;
            }
            if ( !color ){
                nextBtn.disabled = true;
                nextBtn.innerHTML = '請選擇手機顔色';
                return;
            }
            if ( !memory ){
                nextBtn.disabled = true;
                nextBtn.innerHTML = '請選擇記憶體大小';
                return;
            }
            if ( ( ( number - 0 ) | 0 ) !== number - 0 ){ // 輸入購買數量是否為正整數
                nextBtn.disabled = true;
                nextBtn.innerHTML = '請輸入正确的購買數量';
                return;
            }
            nextBtn.disabled = false;
            nextBtn.innerHTML = '放入購物車';
        }
    }
})();


// 各對象各自與中介者進行互動,對象之間不直接互動
colorSelect.onchange = function(){
    mediator.changed( this );
};

memorySelect.onchange = function(){
    mediator.changed( this );
};

numberInput.oninput = function(){
    mediator.changed( this );
};