javascript设计模式之策略模式
一. 认识策略模式
策略模式的定义:定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。
策略模式是开发中常用的第二种设计模式,它在开发中非常常见,由两部分组成。第一部分是策略类,封装了许多具体的,相似的算法。第二部分是环境类,接受客户请求,随后将请求委托给策略类。说的通俗一点就是将相同算法的函数存放在一个包装里边,每个函数用相同的方式拿出来,就叫做策略模式。下面我们来通过代码实现深入了解一下。
二. 具体实现和思想
假如需要实现一个计算员工奖金的程序,效绩为 s 则发基本工资的4倍,a 则3倍,以此类推,那么我们正常实现该代码,是通过判断分支语句来实现。
1. 通过分支实现
let bonus = function (performance, salary) { if(performance === "s") { return salary*4; } if(performance === "a") { return salary*3; } if(performance === "b") { return salary*2; } }
分析:该实现存在显著的缺点,如果随着效绩 的扩展,比如增加c,d,e, if 分支不断累加,使得代码越来越庞大。
因此我们使用策略模式来重构代码。
2.使用策略模式实现
let performances = function () {}; performances.prototype.calculate = function ( salary ) { return salary*4 } let performancea = function () {}; performancea.prototype.calculate = function ( salary ) { return salary*3 } let performanceb = function () {}; performanceb.prototype.calculate = function ( salary ) { return salary*2 } let performancec = function () {}; performancec.prototype.calculate = function ( salary ) { return salary*1 } let bonus = function () { this.salary = null; // 原始工资 this.strategy = null; // 原始绩效 } bonus.prototype.setsalary = function ( salary ) { this.salary = salary; } bonus.prototype.setstrategy = function ( strategy ) { this.strategy = strategy; } bonus.prototype.getbonus = function () { if(!this.strategy) { throw new error("未设置绩效"); } return this.strategy.calculate(this.salary); } let bonus = new bonus(); bonus.setsalary(10000); bonus.setstrategy(new performances()); console.log(bonus.getbonus());
分析:重构后,我们将每种绩效算法单独成一个函数,需要计算某种绩效时只需要将其传入 getbonus 函数中,去掉了 if 分支,减少了性能消耗,并且使代码有了弹性,随时增加其他绩效,不需要更改原代码。
主要思想:这段代码基于面向对象语言,引入了多态的概念,不适用于js。
3. javascript 版本的策略模式
// js中函数也是对象,直接将 strategy 定义为函数 let strategy = { "s": function ( salary ){ return salary*4; }, "a": function ( salary ) { return salary*3; }, "b": function ( salary ) { return salary*2; } } let calculatebonus = function ( level, salary ) { return strategy[ level ]( salary ); } console.log(calculatebonus('a', 20000)) // 6000
分析:js 的对象可以直接创建,将函数封装进去,这样一来,代码显得清晰简洁。代码的复用,弹性也随之变强。
以上就是 js 设计模式策略模式的主要思想和实现,他在应用中有两个主要的作用,一是策略模式实现晃动动画;二是实现表单验证,有能力有兴趣的小伙伴可以往下看。
三. 策略模式的实际运用
1. 使用策略模式实现缓存动画
// 缓动算法 let tween = { linear (t, b, c, d) { return c*t/d + b; }, easein (t, b, c, d) { return c*(t /= d) *t + b; }, strongeasein (t, b, c, d) { return c*(t /= d) *t *t *t *t + b; } } // 定义一个动画类,参数为要运动的 dom 节点 let animate = function ( dom ) { this.dom = dom; this.starttime = 0; this.startpos = 0; this.endpos = 0; this.propertyname = null; 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; this.endpos = endpos; this.duration = duration; this.easing = tween[easing]; let self = this; let timeid = setinterval(() => { if( self.step() === false){ clearinterval(timeid); } }, 19); } // 实现小球每一帧要做的事情 animate.prototype.step = function () { let t =+ new date; if(t>this.starttime + this.duration){ this.update(this.endpos); return false; } let pos = this.easing(t - this.starttime, this.startpos, this.endpos - this.startpos, this.duration); this.update(pos); } animate.prototype.update = function (pos) { this.dom.style[this.propertyname] = pos + 'px'; } let test = function () { let div = document.getelementbyid('div'); let animate = new animate(div); animate.start('left', 500, 1000, 'strongeasein'); // animate.start('top', 1500, 500, 'strongeasein'); } test();
2. 使用策略模式进行表单验证
let strategies = { isnonempty ( value, errormsg) { // 判断是否为空 if(value === '') { return errormsg; } }, minlength (value, length, errormsg){ if (value.length < length) { return errormsg; } } } let dom = document.forms[0].acount; let validatarfunc = function () { let validator = new validator(); // 添加校验规则 validator.add(dom, 'isnonempty', '用户名不能为空!'); let errormsg = validator.start(); return errormsg; // 返回校验结果 } // 实现表单校验保存类 let validator = function () { this.cache = []; // 保存校验规则 } validator.prototype.add = function (dom, rule, errormsg) { let ary = rule.split(':'); this.cache.push( function(){ let strategy = ary.shift(); ary.unshift(dom.value); ary.push( errormsg ); return strategies[strategy].apply(dom, ary); }) } validator.prototype.start = function () { for(let i = 0, validatorfunc; validatorfunc = this.cache[i++];){ let msg = validatorfunc(); if( msg ) { return msg; } } } document.forms[0].addeventlistener('submit', (e) =>{ let errormsg = validatarfunc(); if(errormsg){ alert(errormsg); e.preventdefault(); } })
分析:第一个实现中是把缓动算法封装在一个对象中,调用他们时便于相互替换,也便于扩展。
第二个实现是将校验规则封装起来。
四. 总结
策略模式利用组合、委托、多态等技术思想,有效避免多重条件选择语句,将算法封装在 strategy 中,使他们易于切换、扩展。
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!