国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

javascript設計模式之中介者模式學習筆記

2019-11-19 17:34:14
字體:
來源:轉載
供稿:網友

 先來理解這么一個問題,假如我們前端開發接的需求是需求方給我們需求,可能一個前端開發會和多個需求方打交道,所以會保持多個需求方的聯系,那么在程序里面就意味著保持多個對象的引用,當程序的規模越大,對象會越來越多,他們之間的關系會越來越復雜,那現在假如現在有一個中介者(假如就是我們的主管)來對接多個需求方的需求,那么需求方只需要把所有的需求給我們主管就可以,主管會依次看我們的工作量來給我們分配任務,這樣的話,我們前端開發就不需要和多個業務方聯系,我們只需要和我們主管(也就是中介)聯系即可,這樣的好處就弱化了對象之間的耦合。

日常生活中的列子:

中介者模式對于我們日常生活中經常會碰到,比如我們去房屋中介去租房,房屋中介人在租房者和房東出租者之間形成一條中介;租房者并不關心租誰的房,房東出租者也并不關心它租給誰,因為有中介,所以需要中介來完成這場交易。

中介者模式的作用是解除對象與對象之間的耦合關系,增加一個中介對象后,所有的相關對象都通過中介者對象來通信,而不是相互引用,所以當一個對象發送改變時,只需要通知中介者對象即可。中介者使各個對象之間耦合松散,而且可以獨立地改變它們之間的交互。

實現中介者的列子如下:

不知道大家有沒有玩過英雄殺這個游戲,最早的時候,英雄殺有2個人(分別是敵人和自己);我們針對這個游戲先使用普通的函數來實現如下:

比如先定義一個函數,該函數有三個方法,分別是win(贏), lose(輸),和die(敵人死亡)這三個函數;只要一個玩家死亡該游戲就結束了,同時需要通知它的對手勝利了; 代碼需要編寫如下:

function Hero(name) {  this.name = name;  this.enemy = null; }Hero.prototype.win = function(){  console.log(this.name + 'Won');}Hero.prototype.lose = function(){  console.log(this.name + 'lose');}Hero.prototype.die = function(){  this.lose();  this.enemy.win();}// 初始化2個對象var h1 = new Hero("朱元璋");var h2 = new Hero("劉伯溫");// 給玩家設置敵人h1.enemy = h2;h2.enemy = h1;// 朱元璋死了 也就輸了h1.die(); // 輸出 朱元璋lose 劉伯溫Won

現在我們再來為游戲添加隊友

比如現在我們來為游戲添加隊友,比如英雄殺有6人一組,那么這種情況下就有隊友,敵人也有3個;因此我們需要區分是敵人還是隊友需要隊的顏色這個字段,如果隊的顏色相同的話,那么就是同一個隊的,否則的話就是敵人;

我們可以先定義一個數組players來保存所有的玩家,在創建玩家之后,循環players來給每個玩家設置隊友或者敵人;

var players = [];

接著我們再來編寫Hero這個函數;代碼如下:

var players = []; // 定義一個數組 保存所有的玩家function Hero(name,teamColor) {  this.friends = [];  //保存隊友列表  this.enemies = [];  // 保存敵人列表  this.state = 'live'; // 玩家狀態  this.name = name;   // 角色名字  this.teamColor = teamColor; // 隊伍的顏色}Hero.prototype.win = function(){  // 贏了  console.log("win:" + this.name);};Hero.prototype.lose = function(){  // 輸了  console.log("lose:" + this.name);};Hero.prototype.die = function(){  // 所有隊友死亡情況 默認都是活著的  var all_dead = true;  this.state = 'dead'; // 設置玩家狀態為死亡  for(var i = 0,ilen = this.friends.length; i < ilen; i+=1) {    // 遍歷,如果還有一個隊友沒有死亡的話,則游戲還未結束    if(this.friends[i].state !== 'dead') {      all_dead = false;       break;    }  }  if(all_dead) {    this.lose(); // 隊友全部死亡,游戲結束    // 循環 通知所有的玩家 游戲失敗    for(var j = 0,jlen = this.friends.length; j < jlen; j+=1) {      this.friends[j].lose();    }    // 通知所有敵人游戲勝利    for(var j = 0,jlen = this.enemies.length; j < jlen; j+=1) {      this.enemies[j].win();    }  }}// 定義一個工廠類來創建玩家 var heroFactory = function(name,teamColor) {  var newPlayer = new Hero(name,teamColor);  for(var i = 0,ilen = players.length; i < ilen; i+=1) {    // 如果是同一隊的玩家    if(players[i].teamColor === newPlayer.teamColor) {      // 相互添加隊友列表      players[i].friends.push(newPlayer);      newPlayer.friends.push(players[i]);    }else {      // 相互添加到敵人列表      players[i].enemies.push(newPlayer);      newPlayer.enemies.push(players[i]);    }  }  players.push(newPlayer);  return newPlayer;};    // 紅隊var p1 = heroFactory("aa",'red'),  p2 = heroFactory("bb",'red'),  p3 = heroFactory("cc",'red'),  p4 = heroFactory("dd",'red');    // 藍隊var p5 = heroFactory("ee",'blue'),  p6 = heroFactory("ff",'blue'),  p7 = heroFactory("gg",'blue'),  p8 = heroFactory("hh",'blue');// 讓紅隊玩家全部死亡p1.die();p2.die();p3.die();p4.die();// lose:dd lose:aa lose:bb lose:cc// win:ee win:ff win:gg win:hh

如上代碼:Hero函數有2個參數,分別是name(玩家名字)和teamColor(隊顏色),

首先我們可以根據隊顏色來判斷是隊友還是敵人;同樣也有三個方法win(贏),lose(輸),和die(死亡);如果每次死亡一個人的時候,循環下該死亡的隊友有沒有全部死亡,如果全部死亡了的話,就輸了,因此需要循環他們的隊友,分別告訴每個隊友中的成員他們輸了,同時需要循環他們的敵人,分別告訴他們的敵人他們贏了;因此每次死了一個人的時候,都需要循環一次判斷他的隊友是否都死亡了;因此每個玩家和其他的玩家都是緊緊耦合在一起了。

下面我們可以使用中介者模式來改善上面的demo;

首先我們仍然定義Hero構造函數和Hero對象原型的方法,在Hero對象的這些原型方法中,不再負責具體的執行的邏輯,而是把操作轉交給中介者對象,中介者對象來負責做具體的事情,我們可以把中介者對象命名為playerDirector;

在playerDirector開放一個對外暴露的接口ReceiveMessage,負責接收player對象發送的消息,而player對象發送消息的時候,總是把自身的this作為參數發送給playerDirector,以便playerDirector 識別消息來自于那個玩家對象。

代碼如下:

var players = []; // 定義一個數組 保存所有的玩家function Hero(name,teamColor) {  this.state = 'live'; // 玩家狀態  this.name = name;   // 角色名字  this.teamColor = teamColor; // 隊伍的顏色}Hero.prototype.win = function(){  // 贏了  console.log("win:" + this.name);};Hero.prototype.lose = function(){  // 輸了  console.log("lose:" + this.name);};// 死亡Hero.prototype.die = function(){  this.state = 'dead';  // 給中介者發送消息,玩家死亡  playerDirector.ReceiveMessage('playerDead',this);}// 移除玩家Hero.prototype.remove = function(){  // 給中介者發送一個消息,移除一個玩家  playerDirector.ReceiveMessage('removePlayer',this);};// 玩家換隊Hero.prototype.changeTeam = function(color) {  // 給中介者發送一個消息,玩家換隊  playerDirector.ReceiveMessage('changeTeam',this,color);};// 定義一個工廠類來創建玩家 var heroFactory = function(name,teamColor) {  // 創建一個新的玩家對象  var newHero = new Hero(name,teamColor);  // 給中介者發送消息,新增玩家  playerDirector.ReceiveMessage('addPlayer',newHero);  return newHero;};var playerDirector = (function(){  var players = {}, // 保存所有的玩家    operations = {}; // 中介者可以執行的操作  // 新增一個玩家操作  operations.addPlayer = function(player) {    // 獲取玩家隊友的顏色    var teamColor = player.teamColor;    // 如果該顏色的玩家還沒有隊伍的話,則新成立一個隊伍    players[teamColor] = players[teamColor] || [];    // 添加玩家進隊伍    players[teamColor].push(player);   };  // 移除一個玩家  operations.removePlayer = function(player){    // 獲取隊伍的顏色    var teamColor = player.teamColor,    // 獲取該隊伍的所有成員    teamPlayers = players[teamColor] || [];    // 遍歷    for(var i = teamPlayers.length - 1; i>=0; i--) {      if(teamPlayers[i] === player) {        teamPlayers.splice(i,1);      }    }  };  // 玩家換隊  operations.changeTeam = function(player,newTeamColor){    // 首先從原隊伍中刪除    operations.removePlayer(player);    // 然后改變隊伍的顏色    player.teamColor = newTeamColor;    // 增加到隊伍中    operations.addPlayer(player);  };  // 玩家死亡operations.playerDead = function(player) {  var teamColor = player.teamColor,  // 玩家所在的隊伍  teamPlayers = players[teamColor];  var all_dead = true;  //遍歷   for(var i = 0,player; player = teamPlayers[i++]; ) {    if(player.state !== 'dead') {      all_dead = false;      break;    }  }  // 如果all_dead 為true的話 說明全部死亡  if(all_dead) {    for(var i = 0, player; player = teamPlayers[i++]; ) {      // 本隊所有玩家lose      player.lose();    }    for(var color in players) {      if(color !== teamColor) {        // 說明這是另外一組隊伍        // 獲取該隊伍的玩家        var teamPlayers = players[color];        for(var i = 0,player; player = teamPlayers[i++]; ) {          player.win(); // 遍歷通知其他玩家win了        }      }    }  }};var ReceiveMessage = function(){  // arguments的第一個參數為消息名稱 獲取第一個參數  var message = Array.prototype.shift.call(arguments);  operations[message].apply(this,arguments);};return {  ReceiveMessage : ReceiveMessage};})();// 紅隊var p1 = heroFactory("aa",'red'),  p2 = heroFactory("bb",'red'),  p3 = heroFactory("cc",'red'),    p4 = heroFactory("dd",'red');      // 藍隊  var p5 = heroFactory("ee",'blue'),    p6 = heroFactory("ff",'blue'),    p7 = heroFactory("gg",'blue'),    p8 = heroFactory("hh",'blue');  // 讓紅隊玩家全部死亡  p1.die();  p2.die();  p3.die();  p4.die();  // lose:aa lose:bb lose:cc lose:dd   // win:ee win:ff win:gg win:hh

我們可以看到如上代碼;玩家與玩家之間的耦合代碼已經解除了,而把所有的邏輯操作放在中介者對象里面進去處理,某個玩家的任何操作不需要去遍歷去通知其他玩家,而只是需要給中介者發送一個消息即可,中介者接受到該消息后進行處理,處理完消息之后會把處理結果反饋給其他的玩家對象。使用中介者模式解除了對象與對象之間的耦合代碼; 使程序更加的靈活.

中介者模式實現購買商品的列子

下面的列子是書上的列子,比如在淘寶或者天貓的列子不是這樣實現的,也沒有關系,我們可以改動下即可,我們最主要來學習下使用中介者模式來實現的思路。

首先先介紹一下業務:在購買流程中,可以選擇手機的顏色以及輸入購買的數量,同時頁面中有2個展示區域,分別顯示用戶剛剛選擇好的顏色和數量。還有一個按鈕動態顯示下一步的操作,我們需要查詢該顏色手機對應的庫存,如果庫存數量小于這次的購買數量,按鈕則被禁用并且顯示庫存不足的文案,反之按鈕高亮且可以點擊并且顯示假如購物車。

HTML代碼如下:

選擇顏色:

  <select id="colorSelect">    <option value="">請選擇</option>    <option value="red">紅色</option>    <option value="blue">藍色</option>  </select>  <p>輸入購買的數量: <input type="text" id="numberInput"/></p>  你選擇了的顏色:<div id="colorInfo"></div>  <p>你輸入的數量: <div id="numberInfo"></div> </p>  <button id="nextBtn" disabled="true">請選擇手機顏色和購買數量</button>

首先頁面上有一個select選擇框,然后有輸入的購買數量輸入框,還有2個展示區域,分別是選擇的顏色和輸入的數量的顯示的區域,還有下一步的按鈕操作;

我們先定義一下:

假設我們提前從后臺獲取到所有顏色手機的庫存量

var goods = {  // 手機庫存  "red": 6,  "blue": 8};

接著 我們下面分別來監聽colorSelect的下拉框的onchange事件和numberInput輸入框的oninput的事件,然后在這兩個事件中作出相應的處理

常規的JS代碼如下:

// 假設我們提前從后臺獲取到所有顏色手機的庫存量var goods = {  // 手機庫存  "red": 6,  "blue": 8};/*我們下面分別來監聽colorSelect的下拉框的onchange事件和numberInput輸入框的oninput的事件,然后在這兩個事件中作出相應的處理*/var colorSelect = document.getElementById("colorSelect"),  numberInput = document.getElementById("numberInput"),  colorInfo = document.getElementById("colorInfo"),  numberInfo = document.getElementById("numberInfo"),  nextBtn = document.getElementById("nextBtn");    // 監聽change事件colorSelect.onchange = function(e){  select();};numberInput.oninput = function(){  select();};function select(){  var color = colorSelect.value,  // 顏色    number = numberInput.value, // 數量    stock = goods[color]; // 該顏色手機對應的當前庫存        colorInfo.innerHTML = color;  numberInfo.innerHTML = number;  // 如果用戶沒有選擇顏色的話,禁用按鈕  if(!color) {    nextBtn.disabled = true;    nextBtn.innerHTML = "請選擇手機顏色";      return;  }  // 判斷用戶輸入的購買數量是否是正整數  var reg = /^/d+$/g;  if(!reg.test(number)) {    nextBtn.disabled = true;    nextBtn.innerHTML = "請輸入正確的購買數量";    return;  }  // 如果當前選擇的數量大于當前的庫存的數量的話,顯示庫存不足  if(number > stock) {    nextBtn.disabled = true;    nextBtn.innerHTML = "庫存不足";    return;  }  nextBtn.disabled = false;  nextBtn.innerHTML = "放入購物車";}

上面的代碼雖然是完成了頁面上的需求,但是我們的代碼都耦合在一起了,目前雖然問題不是很多,假如隨著以后需求的改變,SKU屬性越來越多的話,比如頁面增加一個或者多個下拉框的時候,代表選擇手機內存,現在我們需要計算顏色,內存和購買數量,來判斷nextBtn是顯示庫存不足還是放入購物車;代碼如下:

HTML代碼如下:

選擇顏色:  <select id="colorSelect">    <option value="">請選擇</option>    <option value="red">紅色</option>    <option value="blue">藍色</option>  </select>  <br/>  <br/>  選擇內存:  <select id="memorySelect">    <option value="">請選擇</option>    <option value="32G">32G</option>    <option value="64G">64G</option>  </select>  <p>輸入購買的數量: <input type="text" id="numberInput"/></p>  你選擇了的顏色:<div id="colorInfo"></div>  你選擇了內存:<div id="memoryInfo"></div>  <p>你輸入的數量: <div id="numberInfo"></div> </p>  <button id="nextBtn" disabled="true">請選擇手機顏色和購買數量</button>

JS代碼變為如下:

// 假設我們提前從后臺獲取到所有顏色手機的庫存量var goods = {  // 手機庫存  "red|32G": 6,  "red|64G": 16,  "blue|32G": 8,  "blue|64G": 18};/*我們下面分別來監聽colorSelect的下拉框的onchange事件和numberInput輸入框的oninput的事件,然后在這兩個事件中作出相應的處理 */var colorSelect = document.getElementById("colorSelect"),  memorySelect = document.getElementById("memorySelect"),  numberInput = document.getElementById("numberInput"),  colorInfo = document.getElementById("colorInfo"),  numberInfo = document.getElementById("numberInfo"),  memoryInfo = document.getElementById("memoryInfo"),  nextBtn = document.getElementById("nextBtn");    // 監聽change事件colorSelect.onchange = function(){  select();};numberInput.oninput = function(){  select();};memorySelect.onchange = function(){  select();  };function select(){  var color = colorSelect.value,  // 顏色    number = numberInput.value, // 數量    memory = memorySelect.value, // 內存    stock = goods[color + '|' +memory]; // 該顏色手機對應的當前庫存        colorInfo.innerHTML = color;  numberInfo.innerHTML = number;  memoryInfo.innerHTML = memory;  // 如果用戶沒有選擇顏色的話,禁用按鈕  if(!color) {    nextBtn.disabled = true;    nextBtn.innerHTML = "請選擇手機顏色";      return;    }    // 判斷用戶輸入的購買數量是否是正整數    var reg = /^/d+$/g;    if(!reg.test(number)) {      nextBtn.disabled = true;      nextBtn.innerHTML = "請輸入正確的購買數量";      return;    }    // 如果當前選擇的數量大于當前的庫存的數量的話,顯示庫存不足    if(number > stock) {      nextBtn.disabled = true;      nextBtn.innerHTML = "庫存不足";      return;    }    nextBtn.disabled = false;    nextBtn.innerHTML = "放入購物車";  }

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 大庆市| 城固县| 确山县| 香港| 黄梅县| 宣武区| 北票市| 星子县| 洛南县| 门头沟区| 宜兴市| 邳州市| 乌恰县| 富平县| 石屏县| 崇仁县| 剑川县| 板桥市| 德令哈市| 泰兴市| 盐城市| 蓬莱市| 连城县| 永善县| 垫江县| 九江县| 新河县| 长白| 利川市| 胶州市| 凤城市| 彰化市| 电白县| 三门县| 黎平县| 保德县| 苏州市| 青浦区| 秀山| 安塞县| 永福县|