iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 15
0
Modern Web

JS Design Pattern 系列 第 15

JS Design Pattern Day15-中介者模式 Mediator(下)

第15天。最近因為一些工作上的因素,常常會跟一些高層一點的主管講話,都會讓人不禁懷疑這些人是不是每天都在假笑呢

今天 中介者模式 我們來結束它吧

我們再舉個中介者模式例子,如果我們今天要做個手機購買網站,功能有可以選擇手機顏色以及購買數量,選擇的內容會被呈現出來,並且做個防呆以免加到購物車的時候出現錯誤。在這裡我們假設已經提前獲取系統後端的庫存資料了,
如果不使用中介者模式的話,可能會這麼做

//庫存資料
var goods = {
    red: 10,
    blue: 15
}
var $colorSelect, $colorResult, $numberInput, $numberResult, $buyBtn;
(function () {
    $colorSelect = createColorSelect();
    $numberInput = createNumberInput();
    $colorResult = createColorResult();
    $numberResult = createNumberResult();
    $buyBtn = createBuyBtn();

    function createBuyBtn() {
        return $('<button>').text('請輸入手機顏色以及數量')
            .attr('disabled', true).appendTo('body').click(function () {
                alert('已加入購物車');
            });
    }

    function createNumberResult() {
        var $text = $('<span>').text('您購買的手機數量是:');
        var $result = $('<span>');
        $('<div>').append($text).append($result).appendTo('body');
        return $result;
    }

    function createColorResult() {
        var $text = $('<span>').text('您選擇的手機顏色是:');
        var $result = $('<span>');
        $('<div>').append($text).append($result).appendTo('body');
        return $result;
    }

    function createColorSelect() {
        var $text = $('<span>').text('選擇手機顏色:');
        var $select = $('<select>');
        ['請選擇', 'red', 'blue'].forEach(function (color) {
            $('<option>').text(color).val(color).appendTo($select);
        });
        $('<div>').append($text).append($select).appendTo('body');
        return $select;
    }

    function createNumberInput() {
        var $text = $('<span>').text('輸入購買數量:');
        var $input = $('<input>');
        $('<div>').append($text).append($input).appendTo('body');
        return $input;
    }
})();

當產生玩畫面物件之後,我們要針對畫面中每一個元素做事件的綁定

$colorSelect.change(function () {
    var color = this.value;
    var number = $numberInput.val();
    var stock = goods[color];
    $colorResult.text(color);

    if (!color) {
        $buyBtn.text('請選擇正確顏色');
        return;
    }
    if (isNaN(parseInt(number))) {
        $buyBtn.text('請輸入正確購買數量');
        return;
    }
    if (number > stock) {
        $buyBtn.text('庫存不足');
        return;
    }
    $buyBtn.text('加入購物車').attr('disabled', false);
});

$numberInput.change(function () {
    var color = $colorSelect.val();
    var number = $(this).val();
    var stock = goods[color];
    $numberResult.text(number);

    if (!color) {
        $buyBtn.text('請選擇正確顏色');
        return;
    }
    if (isNaN(parseInt(number))) {
        $buyBtn.text('請輸入正確購買數量');
        return;
    }
    if (number > stock) {
        $buyBtn.text('庫存不足');
        return;
    }
    $buyBtn.text('加入購物車').attr('disabled', false);
});

可以看到今天只有兩個輸入點以及三個依照狀態顯示的元素就會讓我們寫起來如此繁瑣,如果畫面元素再多一些實作起來就會更加讓人手忙腳亂,我們用中介者模式來調整看看:
首先一樣產生畫面元素,注意產生之後會return一個物件內包含change key,這個change內容則是實作所有元素觸發事件後要處理的內容

var $colorSelect, $colorResult, $numberInput, $numberResult, $buyBtn;
var mediator = (function () {
    $colorSelect = createColorSelect();
    $numberInput = createNumberInput();
    $colorResult = createColorResult();
    $numberResult = createNumberResult();
    $buyBtn = createBuyBtn();
    //只有這個return有變動,其他部份都一樣
    return {
        change: function ($element) {
            var color = $colorSelect.val();
            var number = $numberInput.val();
            var stock = goods[color];
            if ($element === $colorSelect) {
                $colorResult.text(color);
            } else if ($element === $numberInput) {
                $numberResult.text(number);
            }
            if (!color) {
                $buyBtn.text('請選擇正確顏色');
                return;
            }
            if (isNaN(parseInt(number))) {
                $buyBtn.text('請輸入正確購買數量');
                return;
            }
            if (number > stock) {
                $buyBtn.text('庫存不足');
                return;
            }
            $buyBtn.text('加入購物車').attr('disabled', false);
        }
    }

    function createBuyBtn() {
        return $('<button>').text('請輸入手機顏色以及數量')
            .attr('disabled', true).appendTo('body').click(function () {
                alert('已加入購物車');
            });
    }

    function createNumberResult() {
        var $text = $('<span>').text('您購買的手機數量是:');
        var $result = $('<span>');
        $('<div>').append($text).append($result).appendTo('body');
        return $result;
    }

    function createColorResult() {
        var $text = $('<span>').text('您選擇的手機顏色是:');
        var $result = $('<span>');
        $('<div>').append($text).append($result).appendTo('body');
        return $result;
    }

    function createColorSelect() {
        var $text = $('<span>').text('選擇手機顏色:');
        var $select = $('<select>');
        ['請選擇', 'red', 'blue'].forEach(function (color) {
            $('<option>').text(color).val(color).appendTo($select);
        });
        $('<div>').append($text).append($select).appendTo('body');
        return $select;
    }

    function createNumberInput() {
        var $text = $('<span>').text('輸入購買數量:');
        var $input = $('<input>');
        $('<div>').append($text).append($input).appendTo('body');
        return $input;
    }
})();

之後物件綁定事件的時候都只要呼叫mediator的change函數就好

$colorSelect.change(function () {
    mediator.change($colorSelect);
});

$numberInput.change(function () {
    mediator.change($numberInput);
});

中介者模式是一種最少知識原則的做法,讓所有物件盡可能不知道彼此之間的存在,在實作上盡可能的移除耦合關係。
但中介者也有缺點,我們的確移除了物件之間的耦合,但也因此提升了中介者物件本身的複雜度。實際上在使用時如果物件之間耦合程度已經到了難以維護階段的話,就可以考慮用中介者模式來進行重構。


上一篇
JS Design Pattern Day14-中介者模式 Mediator(上)
下一篇
JS Design Pattern Day16-裝飾者模式 Decorator(上)
系列文
JS Design Pattern 30

尚未有邦友留言

立即登入留言