设计模式 - 策略模式
策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
策略模式定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。
将不变的部分和变化的部分隔开是每个设计模式的主题。策略模式的目的就是将算法的实现和算法的使用分离开来。
策略模式包含三个角色:
Context:环境类
Strategy:抽象策略类
ConcreteStrategy:具体抽象类
例子:
策略模式在js中最常见、使用最多的就是多重表单校验功能
1 <html> 2 <head> 3 <title>策略模式-校验表单</title> 4 <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> 5 </head> 6 7 <body> 8 <form id="registerForm" method="post" action=""> 9 用户名: 10 <input type="text" name="userName"> 密码: 11 <input type="text" name="password"> 手机号码: 12 <input type="text" name="phoneNumber"> 13 <button type="submit">提交</button> 14 </form> 15 16 <script> 17 // 策略对象 18 let strategies = { 19 isNoEmpty: function (value, errorMsg) { 20 if (value === '') { 21 return errorMsg; 22 } 23 }, 24 isNoSpace: function (value, errorMsg) { 25 if (value.trim() === '') { 26 return errorMsg; 27 } 28 }, 29 minLength: function (value, length, errorMsg) { 30 if (value.trim().length < length) { 31 return errorMsg; 32 } 33 }, 34 maxLength: function (value, length, errorMsg) { 35 if (value.length > length) { 36 return errorMsg; 37 } 38 }, 39 isMobile: function (value, errorMsg) { 40 if (!/^1[3456789]\d{9}$/.test(value)) { 41 return errorMsg; 42 } 43 } 44 } 45 46 47 class Validator{ 48 constructor(){ 49 this.cache = []; 50 } 51 } 52 53 54 Validator.prototype.add = function (dom, rules) { 55 let self = this; 56 for (let i = 0, rule; rule = rules[i++];) { 57 (function (rule) { 58 var strategyAry = rule.strategy.split(':'); 59 var errorMsg = rule.errorMsg; 60 self.cache.push(function () { 61 var strategy = strategyAry.shift(); 62 strategyAry.unshift(dom.value); 63 strategyAry.push(errorMsg); 64 return strategies[strategy].apply(dom, strategyAry); 65 }) 66 })(rule) 67 } 68 }; 69 70 Validator.prototype.start = function () { 71 for (let i = 0, validatorFunc; validatorFunc = this.cache[i++];) { 72 let errorMsg = validatorFunc(); 73 if (errorMsg) { 74 return errorMsg; 75 } 76 } 77 }; 78 79 80 let validataFunc = function () { 81 var validator = new Validator(); 82 // 用户名 83 validator.add(registerForm.userName, [{ 84 strategy: 'isNoEmpty', 85 errorMsg: '用户名不可为空' 86 }, { 87 strategy: 'isNoSpace', 88 errorMsg: '不允许以空白字符命名' 89 }, { 90 strategy: 'minLength:2', 91 errorMsg: '用户名长度不能小于2位' 92 }]); 93 94 //密码 95 validator.add(registerForm.password, [{ 96 strategy: 'minLength:6', 97 errorMsg: '密码长度不能小于6位' 98 }]); 99 100 //手机号 101 validator.add(registerForm.phoneNumber, [{ 102 strategy: 'isMobile', 103 errorMsg: '请输入正确的手机号码格式' 104 }]); 105 let errorMsg = validator.start(); 106 return errorMsg; 107 } 108 109 110 // 调用代码 111 let registerForm = document.getElementById('registerForm'); 112 registerForm.onsubmit = function () { 113 let errorMsg = validataFunc(); 114 if (errorMsg) { 115 alert(errorMsg); 116 return false; 117 } 118 } 119 </script> 120 </body> 121 122 </html>
优点
1.策略模式可以有效的避免多层判断语句
2.策略模式讲每个算法独立封装,易于理解和拓展,对"开闭原则"完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
3.策略模式中的算法也可以复用在系统的其它地方,从而避免许多重复的复制粘贴工作。
缺点
1.要使用策略模式,必须要知道全部的策略类,这样才能找到合适的策略类
2.策略模式会定义很多策略对象和策略类
策略模式与js
在JS中除了使用类来封装算法之外,也可以通过函数来实现。实际上在JS中,策略模式已经融合到了语言本身当中,我们经常使用函数来封装不同的行为和算法,并且将他传入到另一个函数中。没当我们调用这些函数的时候,不同的函数会返回不同的结果,所以其实策略模式在JS中就成了一种隐形的模式。