设计模式-中介者模式

面向对象设计鼓励把对象划分成更小的粒度,每个对象负责一个特定的功能,这有助于增强对象的可复用性。但由于这些细粒度对象之间的联系激增,又有可能会反过来降低它们的可复用性。当程序的规模增大,对象会越来越多,它们之间的关系也越来越复杂,难免会形成网状的交叉引用。如图

中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。中介者使各对象之间耦合松散,而且可以独立地改变它们之间的交互。如图

假设我们正在编写一个手机购买的页面,在购买流程中,可以选择手机的颜色、内存大小以及输入购买数量,同时页面中有三个展示区域,分别向用户展示刚刚选择好的颜色、内存和数量。还有一个按钮动态显示下一步的操作,我们需要查询该颜色手机对应的库存,如果库存数量少于这次的购买数量,按钮将被禁用并且显示库存不足,反之按钮可以点击并且显示放入购物车

<!DOCTYPE html>
<html>
<body>
  <div>
    颜色: <select id="colorSelect">
      <option value="">请选择</option>
      <option value="red">红色</option>
      <option value="blue">蓝色</option>
    </select>
    内存: <select id="memorySelect">
      <option value="">请选择</option>
      <option value="16G">16G</option>
      <option value="32G">32G</option>
    </select>
    数量: <input type="number" id="numberInput" />
  </div>
  您选择了颜色: <div id="colorInfo"></div><br />
  您选择了内存: <div id="memoryInfo"></div><br />
  您输入了数量: <div id="numberInfo"></div><br />
  <button id="nextBtn" disabled="true">请选择手机颜色和购买数量</button>
</body>
<script>
var goods = { // 手机库存
  "red|32G": 3,
  "red|16G": 0,
  "blue|32G": 1,
  "blue|16G": 6
};

  // {"red|32G": 3, "red|16G": 0,"blue|32G": 1,"blue|16G": 6}
  // [['red', 'blue'], ['32G', '16G']]
function getSku(obj) {
  var keys = Object.keys(obj),
    skuType = (keys.length && keys[0].split('|')) || [],
    arr = [];
  skuType.forEach(function(item, index){
    arr.push([]); // 根据SKU类型,确认二维数组数量
    keys.forEach(function(item) {
      // 第一个数组存储颜色,第二数组存储内存,依次类推
      var sku = item.split('|')[index]
      if(arr[index].indexOf(sku) == -1) { 
        arr[index].push(sku)
      }
    })
  })
  return arr;
}

console.log(getSku(goods))
// 中介者
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 (!(/(^[1-9]\d*$)/.test(number))) {
        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);
};
</script>
</html>

使用中介者模式的优势很明显,颜色、内存和数量选择之间没有复杂的相互引用,所有的逻辑操作都由mediator对象集中管理。如果后期SKU又新增了CPU选择项,只需要稍微改动mediator对象

var goods = { // 手机库存
  "red|32G|800": 3, // 颜色 red,内存 32G,cpu800,对应库存数量为 3
  "red|16G|801": 0,
  "blue|32G|800": 1,
  "blue|16G|801": 6
};

var mediator = (function() {
  // 略
  var cpuSelect = document.getElementById('cpuSelect');
  return {
    change: function(obj) {
      // 略
      var cpu = cpuSelect.value,
        stock = goods[color + '|' + memory + '|' + cpu];
      if (obj === cpuSelect) {
        cpuInfo.innerHTML = cpu;
      }
      // 略
    }
  }
})();

# 设计模式

发布于 2018-10-16

更新于 2018-10-18

浏览105次

    欢迎留言交流