亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

javascript設計模式之策略模式學習筆記

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

1. 理解javascript中的策略模式

策略模式的定義是:定義一系列的算法,把它們一個個封裝起來,并且使它們可以相互替換。

使用策略模式的優點如下:

優點:

      1. 策略模式利用組合,委托等技術和思想,有效的避免很多if條件語句。

      2. 策略模式提供了開放-封閉原則,使代碼更容易理解和擴展。

      3. 策略模式中的代碼可以復用。

一:使用策略模式計算獎金;

下面的demo是我在書上看到的,但是沒有關系,我們只是來理解下策略模式的使用而已,我們可以使用策略模式來計算獎金問題;

比如公司的年終獎是根據員工的工資和績效來考核的,績效為A的人,年終獎為工資的4倍,績效為B的人,年終獎為工資的3倍,績效為C的人,年終獎為工資的2倍;現在我們使用一般的編碼方式會如下這樣編寫代碼:

var calculateBouns = function(salary,level) {  if(level === 'A') {    return salary * 4;  }  if(level === 'B') {    return salary * 3;  }  if(level === 'C') {    return salary * 2;  }};// 調用如下:console.log(calculateBouns(4000,'A')); // 16000console.log(calculateBouns(2500,'B')); // 7500

第一個參數為薪資,第二個參數為等級;

代碼缺點如下:

calculateBouns 函數包含了很多if-else語句。

calculateBouns 函數缺乏彈性,假如還有D等級的話,那么我們需要在calculateBouns 函數內添加判斷等級D的if語句;

算法復用性差,如果在其他的地方也有類似這樣的算法的話,但是規則不一樣,我們這些代碼不能通用。

2. 使用組合函數重構代碼

組合函數是把各種算法封裝到一個個的小函數里面,比如等級A的話,封裝一個小函數,等級為B的話,也封裝一個小函數,以此類推;如下代碼:

var performanceA = function(salary) {  return salary * 4;};var performanceB = function(salary) {  return salary * 3;};    var performanceC = function(salary) {  return salary * 2};var calculateBouns = function(level,salary) {  if(level === 'A') {    return performanceA(salary);  }  if(level === 'B') {    return performanceB(salary);  }  if(level === 'C') {    return performanceC(salary);  }};// 調用如下console.log(calculateBouns('A',4500)); // 18000

代碼看起來有點改善,但是還是有如下缺點:

calculateBouns 函數有可能會越來越大,比如增加D等級的時候,而且缺乏彈性。

3. 使用策略模式重構代碼

策略模式指的是 定義一系列的算法,把它們一個個封裝起來,將不變的部分和變化的部分隔開,實際就是將算法的使用和實現分離出來;算法的使用方式是不變的,都是根據某個算法取得計算后的獎金數,而算法的實現是根據績效對應不同的績效規則;

一個基于策略模式的程序至少由2部分組成,第一個部分是一組策略類,策略類封裝了具體的算法,并負責具體的計算過程。第二個部分是環境類Context,該Context接收客戶端的請求,隨后把請求委托給某一個策略類。我們先使用傳統面向對象來實現;

如下代碼:

var performanceA = function(){};performanceA.prototype.calculate = function(salary) {  return salary * 4;};   var performanceB = function(){};performanceB.prototype.calculate = function(salary) {  return salary * 3;};var performanceC = function(){};performanceC.prototype.calculate = function(salary) {  return salary * 2;};// 獎金類var Bouns = function(){  this.salary = null;  // 原始工資  this.levelObj = null; // 績效等級對應的策略對象};Bouns.prototype.setSalary = function(salary) {  this.salary = salary; // 保存員工的原始工資};Bouns.prototype.setlevelObj = function(levelObj){  this.levelObj = levelObj; // 設置員工績效等級對應的策略對象};// 取得獎金數Bouns.prototype.getBouns = function(){  // 把計算獎金的操作委托給對應的策略對象  return this.levelObj.calculate(this.salary);};var bouns = new Bouns();bouns.setSalary(10000);bouns.setlevelObj(new performanceA()); // 設置策略對象console.log(bouns.getBouns()); // 40000    bouns.setlevelObj(new performanceB()); // 設置策略對象console.log(bouns.getBouns()); // 30000

如上代碼使用策略模式重構代碼,可以看到代碼職責更新分明,代碼變得更加清晰。

4. Javascript版本的策略模式

//代碼如下:var obj = {    "A": function(salary) {      return salary * 4;    },    "B" : function(salary) {      return salary * 3;    },    "C" : function(salary) {      return salary * 2;    } };var calculateBouns =function(level,salary) {  return obj[level](salary);};console.log(calculateBouns('A',10000)); // 40000

可以看到代碼更加簡單明了;

策略模式指的是定義一系列的算法,并且把它們封裝起來,但是策略模式不僅僅只封裝算法,我們還可以對用來封裝一系列的業務規則,只要這些業務規則目標一致,我們就可以使用策略模式來封裝它們;

表單效驗

比如我們經常來進行表單驗證,比如注冊登錄對話框,我們登錄之前要進行驗證操作:比如有以下幾條邏輯:

用戶名不能為空

密碼長度不能小于6位。

手機號碼必須符合格式。

比如HTML代碼如下:

<form action = "http://www.baidu.com" id="registerForm" method = "post">    <p>      <label>請輸入用戶名:</label>      <input type="text" name="userName"/>    </p>    <p>      <label>請輸入密碼:</label>      <input type="text" name="password"/>    </p>    <p>      <label>請輸入手機號碼:</label>      <input type="text" name="phoneNumber"/>    </p></form>

我們正常的編寫表單驗證代碼如下:

var registerForm = document.getElementById("registerForm");registerForm.onsubmit = function(){  if(registerForm.userName.value === '') {    alert('用戶名不能為空');    return;  }  if(registerForm.password.value.length < 6) {    alert("密碼的長度不能小于6位");    return;  }  if(!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {    alert("手機號碼格式不正確");    return;  }}


但是這樣編寫代碼有如下缺點:

1.registerForm.onsubmit 函數比較大,代碼中包含了很多if語句;

2.registerForm.onsubmit 函數缺乏彈性,如果增加了一種新的效驗規則,或者想把密碼的長度效驗從6改成8,我們必須改registerForm.onsubmit 函數內部的代碼。違反了開放-封閉原則。

3. 算法的復用性差,如果在程序中增加了另外一個表單,這個表單也需要進行一些類似的效驗,那么我們可能又需要復制代碼了;

下面我們可以使用策略模式來重構表單效驗;

第一步我們先來封裝策略對象;如下代碼:

var strategy = {  isNotEmpty: function(value,errorMsg) {    if(value === '') {      return errorMsg;    }  },  // 限制最小長度  minLength: function(value,length,errorMsg) {    if(value.length < length) {      return errorMsg;    }  },  // 手機號碼格式  mobileFormat: function(value,errorMsg) {    if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {      return errorMsg;    }  } };

接下來我們準備實現Validator類,Validator類在這里作為Context,負責接收用戶的請求并委托給strategy 對象,如下代碼:

var Validator = function(){  this.cache = []; // 保存效驗規則};Validator.prototype.add = function(dom,rule,errorMsg) {  var str = rule.split(":");  this.cache.push(function(){    // str 返回的是 minLength:6     var strategy = str.shift();    str.unshift(dom.value); // 把input的value添加進參數列表    str.push(errorMsg); // 把errorMsg添加進參數列表    return strategys[strategy].apply(dom,str);  });};Validator.prototype.start = function(){  for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {    var msg = validatorFunc(); // 開始效驗 并取得效驗后的返回信息    if(msg) {      return msg;    }  }};

Validator類在這里作為Context,負責接收用戶的請求并委托給strategys對象。上面的代碼中,我們先創建一個Validator對象,然后通過validator.add方法往validator對象中添加一些效驗規則,validator.add方法接收3個參數,如下代碼:

validator.add(registerForm.password,'minLength:6','密碼長度不能小于6位');

registerForm.password 為效驗的input輸入框dom節點;

minLength:6: 是以一個冒號隔開的字符串,冒號前面的minLength代表客戶挑選的strategys對象,冒號后面的數字6表示在效驗過程中所必須驗證的參數,minLength:6的意思是效驗 registerForm.password 這個文本輸入框的value最小長度為6位;如果字符串中不包含冒號,說明效驗過程中不需要額外的效驗信息;

第三個參數是當效驗未通過時返回的錯誤信息;

當我們往validator對象里添加完一系列的效驗規則之后,會調用validator.start()方法來啟動效驗。如果validator.start()返回了一個errorMsg字符串作為返回值,說明該次效驗沒有通過,此時需要registerForm.onsubmit方法返回false來阻止表單提交。下面我們來看看初始化代碼如下:

var validateFunc = function(){  var validator = new Validator(); // 創建一個Validator對象  /* 添加一些效驗規則 */  validator.add(registerForm.userName,'isNotEmpty','用戶名不能為空');  validator.add(registerForm.password,'minLength:6','密碼長度不能小于6位');  validator.add(registerForm.userName,'mobileFormat','手機號碼格式不正確');  var errorMsg = validator.start(); // 獲得效驗結果  return errorMsg; // 返回效驗結果};var registerForm = document.getElementById("registerForm");registerForm.onsubmit = function(){  var errorMsg = validateFunc();  if(errorMsg){    alert(errorMsg);    return false;  }}

下面是所有的代碼如下:

var strategys = {  isNotEmpty: function(value,errorMsg) {    if(value === '') {      return errorMsg;    }  },  // 限制最小長度  minLength: function(value,length,errorMsg) {    if(value.length < length) {      return errorMsg;    }  },  // 手機號碼格式  mobileFormat: function(value,errorMsg) {    if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {      return errorMsg;    }  } };var Validator = function(){  this.cache = []; // 保存效驗規則};Validator.prototype.add = function(dom,rule,errorMsg) {  var str = rule.split(":");  this.cache.push(function(){    // str 返回的是 minLength:6     var strategy = str.shift();    str.unshift(dom.value); // 把input的value添加進參數列表    str.push(errorMsg); // 把errorMsg添加進參數列表    return strategys[strategy].apply(dom,str);  });};Validator.prototype.start = function(){  for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {    var msg = validatorFunc(); // 開始效驗 并取得效驗后的返回信息    if(msg) {      return msg;    }  }};var validateFunc = function(){  var validator = new Validator(); // 創建一個Validator對象  /* 添加一些效驗規則 */  validator.add(registerForm.userName,'isNotEmpty','用戶名不能為空');  validator.add(registerForm.password,'minLength:6','密碼長度不能小于6位');  validator.add(registerForm.userName,'mobileFormat','手機號碼格式不正確');  var errorMsg = validator.start(); // 獲得效驗結果  return errorMsg; // 返回效驗結果};var registerForm = document.getElementById("registerForm");registerForm.onsubmit = function(){  var errorMsg = validateFunc();  if(errorMsg){    alert(errorMsg);    return false;  }};

如上使用策略模式來編寫表單驗證代碼可以看到好處了,我們通過add配置的方式就完成了一個表單的效驗;這樣的話,那么代碼可以當做一個組件來使用,并且可以隨時調用,在修改表單驗證規則的時候,也非常方便,通過傳遞參數即可調用;

給某個文本輸入框添加多種效驗規則,上面的代碼我們可以看到,我們只是給輸入框只能對應一種效驗規則,比如上面的我們只能效驗輸入框是否為空,validator.add(registerForm.userName,'isNotEmpty','用戶名不能為空');但是如果我們既要效驗輸入框是否為空,還要效驗輸入框的長度不要小于10位的話,那么我們期望需要像如下傳遞參數:

validator.add(registerForm.userName,[{strategy:'isNotEmpty',errorMsg:'用戶名不能為空'},{strategy: 'minLength:6',errorMsg:'用戶名長度不能小于6位'}])

我們可以編寫代碼如下:

// 策略對象var strategys = {  isNotEmpty: function(value,errorMsg) {    if(value === '') {      return errorMsg;    }  },  // 限制最小長度  minLength: function(value,length,errorMsg) {    if(value.length < length) {      return errorMsg;    }  },  // 手機號碼格式  mobileFormat: function(value,errorMsg) {    if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {      return errorMsg;    }  } };var Validator = function(){  this.cache = []; // 保存效驗規則};Validator.prototype.add = function(dom,rules) {  var self = this;  for(var i = 0, rule; rule = rules[i++]; ){    (function(rule){      var strategyAry = rule.strategy.split(":");      var errorMsg = rule.errorMsg;      self.cache.push(function(){        var strategy = strategyAry.shift();        strategyAry.unshift(dom.value);        strategyAry.push(errorMsg);        return strategys[strategy].apply(dom,strategyAry);      });    })(rule);  }};Validator.prototype.start = function(){  for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {  var msg = validatorFunc(); // 開始效驗 并取得效驗后的返回信息  if(msg) {    return msg;  }  }};// 代碼調用var registerForm = document.getElementById("registerForm");var validateFunc = function(){  var validator = new Validator(); // 創建一個Validator對象  /* 添加一些效驗規則 */  validator.add(registerForm.userName,[    {strategy: 'isNotEmpty',errorMsg:'用戶名不能為空'},    {strategy: 'minLength:6',errorMsg:'用戶名長度不能小于6位'}  ]);  validator.add(registerForm.password,[    {strategy: 'minLength:6',errorMsg:'密碼長度不能小于6位'},  ]);  validator.add(registerForm.phoneNumber,[    {strategy: 'mobileFormat',errorMsg:'手機號格式不正確'},  ]);  var errorMsg = validator.start(); // 獲得效驗結果  return errorMsg; // 返回效驗結果};// 點擊確定提交registerForm.onsubmit = function(){  var errorMsg = validateFunc();  if(errorMsg){    alert(errorMsg);    return false;  }}

注意:如上代碼都是按照書上來做的,都是看到書的代碼,最主要我們理解策略模式實現,比如上面的表單驗證功能是這樣封裝的代碼,我們平時使用jquery插件表單驗證代碼原來是這樣封裝的,為此我們以后也可以使用這種方式來封裝表單等學習;

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人久久久| 久久久亚洲国产| 91av在线播放| 国产在线98福利播放视频| 日韩成人激情在线| 久久久国产一区二区| 国产午夜精品视频免费不卡69堂| 国产视频欧美视频| 欧美午夜精品久久久久久久| 麻豆国产va免费精品高清在线| 欧美丰满片xxx777| 精品久久久久久久大神国产| 久久久免费电影| 欧美激情xxxx性bbbb| 亚洲一区国产精品| xvideos国产精品| 欧美激情亚洲激情| 欧美黑人xxxⅹ高潮交| 91免费看视频.| 欧美日韩成人精品| 91在线观看免费高清| 91九色视频导航| 91色中文字幕| 奇米成人av国产一区二区三区| 国产精品视频不卡| 97成人精品区在线播放| 亚洲精品乱码久久久久久按摩观| 日韩精品亚洲元码| 久久久久久久一| 国产精品xxx视频| 一区国产精品视频| 日韩av在线导航| 国产精品高清在线| 日韩欧美福利视频| 欧美电影免费观看高清| 久久免费国产精品1| 欧美日韩亚洲一区二区| 国产成人精品在线观看| 中文国产成人精品| 国产97在线|日韩| 欧美精品videossex88| 国产精品678| 亚洲成人精品久久久| 欧美另类69精品久久久久9999| 欧洲永久精品大片ww免费漫画| 色诱女教师一区二区三区| 国产香蕉一区二区三区在线视频| 国内偷自视频区视频综合| 国产精品老牛影院在线观看| 日韩中文在线中文网在线观看| 日韩在线观看网址| 国产综合在线视频| 亚洲自拍另类欧美丝袜| 欧美性猛交xxxx富婆弯腰| 亚洲欧洲国产一区| 国产精品入口日韩视频大尺度| 国产精品视频免费在线观看| 久久久亚洲欧洲日产国码aⅴ| 亚洲网在线观看| 国产玖玖精品视频| 国产中文字幕91| 97不卡在线视频| 性欧美长视频免费观看不卡| 91精品在线播放| 久久免费福利视频| 亚洲黄色在线看| 理论片在线不卡免费观看| 久久久亚洲精品视频| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产不卡av在线免费观看| 中文亚洲视频在线| 色综合久综合久久综合久鬼88| 欧美日韩激情视频8区| 亚洲精品视频久久| 亚洲美女精品成人在线视频| 亚洲第一综合天堂另类专| 欧美日韩在线视频首页| 国产欧美欧洲在线观看| 国产一区二区三区视频在线观看| 色婷婷综合久久久久中文字幕1| 成人97在线观看视频| 日韩av免费看网站| 国产精品入口福利| 色噜噜国产精品视频一区二区| 456国产精品| 亚洲日本中文字幕免费在线不卡| 欧美做爰性生交视频| 欧美精品一区二区免费| 欧美电影免费在线观看| 亚洲一区国产精品| 欧美国产极速在线| 亚洲国产精品中文| 欧美人成在线视频| 国产视频久久久久| 亚洲va久久久噜噜噜久久天堂| 欧美床上激情在线观看| 久久亚洲国产精品成人av秋霞| 国产精品黄视频| 97福利一区二区| 久久视频免费观看| 久久精品99久久香蕉国产色戒| 欧美一级淫片播放口| 丰满岳妇乱一区二区三区| 另类视频在线观看| 国产视频观看一区| 国产精品99久久久久久久久久久久| 亚洲欧美在线磁力| 精品视频www| 久久国内精品一国内精品| 成人国产精品一区二区| 国产亚洲精品久久久久久| 日韩www在线| 亚洲自拍偷拍区| 人妖精品videosex性欧美| 欧美激情va永久在线播放| 亚洲欧美国内爽妇网| 久久精品色欧美aⅴ一区二区| 欧美成人午夜免费视在线看片| 亚洲男人天堂九九视频| 国产精品自拍网| 精品久久久91| 伊人久久精品视频| 成人做爽爽免费视频| 欧美性极品少妇精品网站| 日韩av在线影院| 91久久精品国产91性色| 成人精品久久一区二区三区| 亚洲一区二区久久久久久久| 热久久这里只有精品| 久99久在线视频| 国产美女91呻吟求| www.日韩av.com| 亚洲天堂男人天堂| 亚洲精品乱码久久久久久按摩观| 性欧美xxxx| 亚洲a中文字幕| 88xx成人精品| 久久综合伊人77777尤物| 国产久一一精品| 成人黄色短视频在线观看| 欧美在线视频导航| 精品国产一区二区三区久久狼5月| 亚洲自拍偷拍网址| 亚洲一区二区三区乱码aⅴ蜜桃女| 最近2019年中文视频免费在线观看| 亚洲激情第一页| 精品国产一区二区三区久久久狼| yellow中文字幕久久| 久久久久久久一区二区三区| 亚洲深夜福利网站| 亚洲第一中文字幕| 91在线免费视频| 亚洲成人激情视频| 日韩在线免费视频| 欧美性猛交99久久久久99按摩| 国产精品久久久久久久电影| 国产精品视频一| 成人xvideos免费视频| 国产精品永久在线| 欧美高清在线播放| 国产精品黄色影片导航在线观看| 国产91色在线|| 丝袜美腿亚洲一区二区| 成人欧美一区二区三区黑人|