最近在看《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. RSYNC @ERROR: AUTH FAILED ON MODULE XXX 解决思路及附录RSYNC常见问题及解决办法

    使用rsync往服务器上传文件时,client报如下异常: @ERROR: auth failed on module XXX rsync error: error starting client-s ...

  2. hadoop(1)---hadoop的介绍和几种模式。

    一.什么是hadoop? Hadoop软件库是一个开源框架,允许使用简单的编程模型跨计算机集群分布式处理大型数据集.它旨在从单个服务器扩展到数千台计算机,每台计算机都提供本地计算和存储.库本身不是依靠 ...

  3. GitLab安装及备份迁移数据

    centos7安装GitLab 下载相应版本rpm包 https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/ 我此处下载9.3.6版本. # w ...

  4. Python 学习随笔 - 1 - 基础数据类型、变量 及 基本运算

    仅有的C语言的基础都是大学时学的: 准备赶潮流,开始学习Python. 随笔记录学习过程中,靠一点点C语言基础难以去理解的地方,以及区别于C语言的地方,做些笔记作为以后参考. Python 解释器直接 ...

  5. EXCEL公式中如何表示回车符?

    问题: 将 id credttm cdno cdamt cashbrid cashrole note 转换为 "id  credttm  cdno   cdamt  cashbrid  ca ...

  6. 《Glibc内存管理》笔记DAY3

    目录 边界标记法 内容来源 边界标记法 /* conversion from malloc headers to user pointers, and back */ #define chunk2me ...

  7. [RK3288] 外接USB设备出现丢数

    CPU:RK3288 系统:Android 5.1 主板外接 USB 接口的外设,经常会出现丢数的现象,这种问题在很多 USB 接口的外设上都遇到过,例如:USB读卡器.USB扫描枪等 有一个共同点是 ...

  8. TortoiseGit进行squash后冲突,如何撤销

    还没有commit之前,需要撤销. 最暴力的,直接用git reset --hard HEAD How to undo a git merge squash? If you run git merge ...

  9. python wmi远程数据获取

  10. 使用Flask构建机器学习模型API

    1. Python环境设置和Flask基础 使用"Anaconda"创建一个虚拟环境.如果你需要在Python中创建你的工作流程,并将依赖项分离出来,或者共享环境设置," ...