天天看點

js設計模式【詳解】—— 政策模式政策模式的定義示範範例1——計算薪資示範範例2——表單校驗

目錄

政策模式的定義

示範範例1——計算薪資

示範範例2——表單校驗 

政策模式的定義

政策模式就是将一系列算法封裝起來,并使它們互相之間可以替換。

優點:

  • 可以有效避免多重條件選擇語句
  • 提供了對開放-封裝原則的完美支援,将方法封裝在獨立的strategy中,使得它們易于切換,易于了解,易于擴充
  • 複用性高

缺點:

  • 增加了許多政策類或者政策對象。
  • 要使用政策模式,必須了解所有的strategy,違反了最少知識原則。

示範範例1——計算薪資

使用政策模式前

var calculateBonus = function( performanceLevel, salary ){
    if ( performanceLevel === 'S' ){
        return salary * 4;
    }
    if ( performanceLevel === 'A' ){
        return salary * 3;
    }
    if ( performanceLevel === 'B' ){
        return salary * 2;
    }
};
calculateBonus( 'B', 20000 ); // 輸出:40000
calculateBonus( 'S', 6000 ); // 輸出:24000
           

雖然代碼看起來簡潔,但是該函數比較龐大,包含了很多if語句,這些語句需要覆寫所有的邏輯分支;該函數缺乏彈性,如果增加了一種新的績效等級C,或者想把績效S的獎金系數改為5,必須深入calculateBonus函數的内部實作,違反開放封閉原則

使用政策模式後

var strategies = {
    "S": function( salary ){
        return salary * 4;
    },
    "A": function( salary ){
        return salary * 3;
    },
    "B": function( salary ){
        return salary * 2;
    }
};
var calculateBonus = function( level, salary ){
    return strategies[ level ]( salary );
};
console.log( calculateBonus( 'S', 20000 ) ); // 輸出:80000
console.log( calculateBonus( 'A', 10000 ) ); // 輸出:30000
           

示範範例2——表單校驗

 使用政策模式前

<html>
<head>
  <title>政策模式-校驗表單</title>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body>
  <form id = "registerForm" method="post" action="http://xxxx.com/api/register">
    使用者名:<input type="text" name="userName">
    密碼:<input type="text" name="password">
    手機号碼:<input type="text" name="phoneNumber">
    <button type="submit">送出</button>
  </form>
  <script type="text/javascript">
    var registerForm = document.getElementById('registerForm');
    registerForm.onsubmit = function() {
      if (registerForm.userName.value === '') {
        alert('使用者名不可為空');
        return false;
      }
      if (registerForm.userName.value === '') {
        alert('使用者名不可為空');
        return false;
      } 
      if (registerForm.userName.value.trim() === '') {
        alert('使用者名不允許以空白字元命名');
        return false;
      } 
      if (registerForm.userName.value.trim().length < 2) {
        alert('使用者名使用者名長度不能小于2位');
        return false;
      } 
      if (registerForm.password.value.trim().length < 6) {
        alert('密碼長度不能小于6位');
        return false;
      }
      if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(registerForm.phoneNumber.value)) {
        alert('請輸入正确的手機号碼格式');
        return errorMsg;
       } 
    }
  </script>
</body>
</html>
           

很明顯的缺點:

  • registerForm.onsubmit 函數比較龐大,包含了很多if語句,這些語句要覆寫所有的校驗規則。
  • 若校驗規則有變,不得不深入到registerForm.onsubmit 函數的内部實作,違反開放-封閉原則。
  • 算法的複用性差。

使用政策模式後

<html>
<head>
  <title>政策模式-校驗表單</title>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body>
  <form id = "registerForm" method="post" action="http://xxxx.com/api/register">
    使用者名:<input type="text" name="userName">
    密碼:<input type="text" name="password">
    手機号碼:<input type="text" name="phoneNumber">
    <button type="submit">送出</button>
  </form>
  <script type="text/javascript">
    // 政策對象
    var strategies = {
      isNoEmpty: function (value, errorMsg) {
        if (value === '') {
          return errorMsg;
        }
      },
      isNoSpace: function (value, errorMsg) {
        if (value.trim() === '') {
          return errorMsg;
        }
      },
      minLength: function (value, length, errorMsg) {
        if (value.trim().length < length) {
          return errorMsg;
        }
      },
      maxLength: function (value, length, errorMsg) {
        if (value.length > length) {
          return errorMsg;
        }
      },
      isMobile: function (value, errorMsg) {
        if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.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 strategies[strategy].apply(dom, strategyAry);
          })
        })(rule)
      }
    };
    Validator.prototype.start = function() {
      for(var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
        var errorMsg = validatorFunc();
        if (errorMsg) {
          return errorMsg;
        }
      }
    };

    // 調用代碼
    var registerForm = document.getElementById('registerForm');

    var validataFunc = function() {
      var validator = new Validator();
      validator.add(registerForm.userName, [{
        strategy: 'isNoEmpty',
        errorMsg: '使用者名不可為空'
      }, {
        strategy: 'isNoSpace',
        errorMsg: '不允許以空白字元命名'
      }, {
        strategy: 'minLength:2',
        errorMsg: '使用者名長度不能小于2位'
      }]);
      validator.add(registerForm.password, [ {
        strategy: 'minLength:6',
        errorMsg: '密碼長度不能小于6位'
      }]);
      validator.add(registerForm.phoneNumber, [{
        strategy: 'isMobile',
        errorMsg: '請輸入正确的手機号碼格式'
      }]);
      var errorMsg = validator.start();
      return errorMsg;
    }

    registerForm.onsubmit = function() {
      var errorMsg = validataFunc();
      if (errorMsg) {
        alert(errorMsg);
        return false;
      }
    }
  </script>
</body>
</html>
           

更多設計模式詳見——js設計模式【詳解】總目錄

https://blog.csdn.net/weixin_41192489/article/details/116154815

繼續閱讀