最近在看《JavaScript设计模式与开发实践》这本书,受益匪浅,小记录一下书中的各个demo,加深理解;

策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

案例1:很多公司的年终奖是根据员工的工资基数和年底绩效情况来发放的。例如,绩效为S 的人年终奖有4 倍工资,绩效为A 的人年终奖有3 倍工资,而绩效为B 的人年终奖是2 倍工资。假设财务部要求我们提供一段代码,来方便他们计算员工的年终奖。用JS实现这个很简单html 代码

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

这个代码是非常简单的,但是缺点很明显:

a、calculateBonus 函数比较庞大,包含了很多if-else 语句,这些语句需要覆盖所有的逻辑分支。

b、calculateBonus 函数缺乏弹性,如果增加了一种新的绩效等级C,或者想把绩效S 的奖金系数改为5,那我们必须深入calculateBonus 函数的内部实现,这是违反开放封闭原则的。

c、算法的复用性差,如果在程序的其他地方需要重用这些计算奖金的算法呢?我们的选择只有复制和粘贴。

这个时候策略模式就用上场了;见代码:

html 代码

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

案例二:实现一个js当中运动的DIV;

实用策略模式实现如下:

html 代码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>javascript策略模式的应用!</title>
</head>
<body>
<div style="position:absolute;background:blue; width: 100px;height: 100px;color: #fff;" id="div">我是div</div>
<script> var tween = {
linear: function(t, b, c, d) {
return c * t / d + b;
},
easeIn: function(t, b, c, d) {
return c * (t /= d) * t + b;
},
strongEaseIn: function(t, b, c, d) {
return c * (t /= d) * t * t * t * t + b;
},
strongEaseOut: function(t, b, c, d) {
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
},
sineaseIn: function(t, b, c, d) {
return c * (t /= d) * t * t + b;
},
sineaseOut: function(t, b, c, d) {
return c * ((t = t / d - 1) * t * t + 1) + b;
}
};
var Animate = function(dom) {
this.dom = dom; // 进行运动的dom 节点
this.startTime = 0; // 动画开始时间
this.startPos = 0; // 动画开始时,dom 节点的位置,即dom 的初始位置
this.endPos = 0; // 动画结束时,dom 节点的位置,即dom 的目标位置
this.propertyName = null; // dom 节点需要被改变的css 属性名
this.easing = null; // 缓动算法
this.duration = null; // 动画持续时间
};
Animate.prototype.start = function(propertyName, endPos, duration, easing) {
this.startTime = +new Date; // 动画启动时间
this.startPos = this.dom.getBoundingClientRect()[propertyName]; // dom 节点初始位置
this.propertyName = propertyName; // dom 节点需要被改变的CSS 属性名
this.endPos = endPos; // dom 节点目标位置
this.duration = duration; // 动画持续事件
this.easing = tween[easing]; // 缓动算法
var self = this;
var timeId = setInterval(function() { // 启动定时器,开始执行动画
if (self.stop() === false) { // 如果动画已结束,则清除定时器
clearInterval(timeId);
}
}, 19);
};
Animate.prototype.stop = function() {
var t = +new Date; // 取得当前时间
if (t >= this.startTime + this.duration) { // (1)
this.update(this.endPos); // 更新小球的CSS 属性值
return false;
}
var pos = this.easing(t - this.startTime, this.startPos,
this.endPos - this.startPos, this.duration);
// pos 为小球当前位置
this.update(pos); // 更新小球的CSS 属性值
};
Animate.prototype.update = function(pos) {
this.dom.style[this.propertyName] = pos + 'px';
}; var div = document.getElementById('div');
var animate = new Animate(div);
animate.start('left', 500, 1000, 'strongEaseOut'); </script>
</body>
</html>

案列三:实现表单验证;

html 代码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<link rel="stylesheet" href="">
</head>
<body>
<form action="http:// xxx.com/register" id="registerForm" method="post">
请输入用户名:<input type="text" name="userName"/ ><br>
请输入密码:<input type="text" name="password"/ ><br> 请输入手机号码:<input type="text" name="phoneNumber"/ ><br>
<button>提交</button><br>
</form>
<script>
var registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function() {
if (registerForm.userName.value === '') {
alert('用户名不能为空');
return false;
}
if (registerForm.password.value.length < 6) {
alert('密码长度不能少于6 位');
return false;
}
if (!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {
alert('手机号码格式不正确');
return false;
}
}
</script>
</body>
</html>

这是一种很常见的代码编写方式,它的缺点跟计算奖金的最初版本一模一样。因此,还是要使用策略模式; 代码如下:

html 代码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<link rel="stylesheet" href="">
</head>
<body>
<form action="http:// xxx.com/register" id="registerForm" method="post">
请输入用户名:<input type="text" name="userName"/ ><br>
请输入密码:<input type="text" name="password"/ ><br> 请输入手机号码:<input type="text" name="phoneNumber"/ ><br>
<button>提交</button><br>
</form>
<script> /***********************策略对象**************************/
var strategies = {
isNonEmpty: function(value, errorMsg) {
if (value === '') {
return errorMsg;
}
},
minLength: function(value, length, errorMsg) {
if (value.length < length) {
return errorMsg;
}
},
isMobile: function(value, errorMsg) {
if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
return errorMsg;
}
}
};
/***********************Validator 类**************************/
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: 'isNonEmpty',
errorMsg: '用户名不能为空'
}, {
strategy: 'minLength:6',
errorMsg: '用户名长度不能小于10 位'
}]);
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>

策略模式是一种常用且有效的设计模式,本章提供了计算奖金、缓动动画、表单校验这三个例子来加深大家对策略模式的理解。从这三个例子中,我们可以总结出策略模式的一些优点。

a、策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。

b、策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的strategy 中,使得它们易于切换,易于理解,易于扩展。

c、策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。

当然,策略模式也有一些缺点,但这些缺点并不严重。可略过。。

javascript策略模式的应用!的更多相关文章

  1. 轻松掌握:JavaScript策略模式

    策略模式 定义:定义一系列的算法,把它们一个个封装成函数,也可把它们作为属性统一封装进一个对象,然后再定义一个方法,该方法可根据参数自动选择执行对应的算法. 一般用于在实现一个功能时,有很多个方案可选 ...

  2. 使用JavaScript策略模式校验表单

    表单校验 Web项目中,登录,注册等等功能都需要表单提交,当把用户的数据提交给后台之前,前端一般要做一些力所能及的校验,比如是否填写,填写的长度,密码是否符合规范等等,前端校验可以避免提交不合规范的表 ...

  3. javascript设计模式--策略模式

    javascript策略模式总结 1.什么是策略模式? 策略模式的定义是:定义一系列的算法,把他们独立封装起来,并且可以相互替换. 例如我们需要写一段代码来计算员工的奖金.当绩效为a时,奖金为工资的5 ...

  4. 第二章 --- 关于Javascript 设计模式 之 策略模式

    这一章节里面,我们会主要的针对JavaScript中的策略模式进行理解和学习 一.定义 策略模式: 定义一系列的算法,把他们封装起来,并且是他们可以相互替换. (这样的大的定义纲领,真的不好理解,特别 ...

  5. javascript 设计模式-----策略模式

    在<javascript设计模式>中,作者并没有向我们介绍策略模式,然而它却是一种在开发中十分常见的设计模式.最常见的就是当我们遇到一个复杂的表单验证的时候,常常需要编写一大段的if和el ...

  6. javascript设计模式实践之策略模式--输入验证

    策略模式中的策略就是一种算法或者业务规则,将这些策略作为函数进行封装,并向外提供统一的调用执行. 先定义一个简单的输入表单: <!DOCTYPE html> <html> &l ...

  7. [设计模式] javascript 之 策略模式

    策略模式说明 定义: 封装一系列的算法,使得他们之间可以相互替换,本模式使用算法独立于使用它的客户的变化. 说明:策略模式,是一种组织算法的模式,核心不在于算法,而在于组织一系列的算法,并且如何去使用 ...

  8. 理解javascript中的策略模式

    理解javascript中的策略模式 策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 使用策略模式的优点如下: 优点:1. 策略模式利用组合,委托等技术和思想,有效 ...

  9. javascript设计模式学习之五——策略模式

    一.策略模式定义: 定义一些列的算法/规则,将它们封装起来,使得它们可以互相替换/组合使用.其目的在于将算法/规则封装起来,将算法/规则的使用与实现分离出来. 通过策略模式,可以减少算法计算过程中大量 ...

随机推荐

  1. linux系列(十二):more命令

    1.命令格式: more [-dlfpcsu ] [-num ] [+/ pattern] [+ linenum] [file] 2.命令功能: more命令和cat的功能一样都是查看文件里的内容,但 ...

  2. qml 3d 纪念那些曾经爬过的坑

    1.使用多position画图时,图形不受控制的问题? 在变量属性设置时Attribute中的attributeBaseType 数据类型一定要和 Buffer中data 数据类型一定要相同. 例如  ...

  3. (转)实验文档5:企业级kubernetes容器云自动化运维平台

    部署对象式存储minio 运维主机HDSS7-200.host.com上: 准备docker镜像 镜像下载地址 复制 12345678910111213141516 [root@hdss7-200 ~ ...

  4. codeforces164A

    Variable, or There and Back Again CodeForces - 164A Life is not easy for the perfectly common variab ...

  5. 【转】Linux下软件安装的几种方式

    转自Linux下软件安装的几种方式 Linux 系统的/usr目录 Linux 软件安装到哪里合适,目录详解 Linux 的软件安装目录是也是有讲究的,理解这一点,在对系统管理是有益的 /usr:系统 ...

  6. 【Java】 HashMap

    Java HashMap 标签(空格分隔): Java source-code hash-map 总结 HashTable的基本数据结构 Entry的hash与table的长度计算indexFor才能 ...

  7. pgpool-II 高可用搭建

    pgpool-II主备流复制的架设1.环境 OS: CentOS release 6.4 (Final)DB: postgresql 9.3.6pgpool服务器: pgpool 172.16.0.2 ...

  8. MacOS系统降级

    从MacOS 10.14 降级到 10.12,下载好系统镜像文件.打开,复制到Application. 准备一个至少8G的U盘,,打开磁盘工具,『抹掉』(格式化)成Mac OS扩展(日志式),名称可随 ...

  9. PHP根据传入的经纬度,和距离范围,返回所有在距离范围内的经纬度的取值范围

    /** * 根据传入的经纬度,和距离范围,返回所有在距离范围内的经纬度的取值范围 * @param float $lng 经度 * @param float $lat 纬度 * @param floa ...

  10. ISO/IEC 9899:2011 条款5——5.2.2 字符显示语义

    5.2.2 字符显示语义 1.活动位置是在一个显示设备上的位置,由fputc函数所输出的下一个字符会出现在那个位置上.写一个打印字符(由isprint函数)到显示设备的意图是为了在活动位置上显示那字符 ...