策略模式
特点 由一个上下文对象负责选择策略,将策略的实现委托给策略类,节省if-else判断分支
实现思路 定义算法(即策略)族,将算法的使用与实现隔离
/* 策略模式 模板 */var strategies = function () { "s1" : function ( arg ) { // body... }, "s2" :function ( arg ) { // body... } //,"s3"...}var context = function ( str, arg ) { return strategies[ str ]( arg );}
实例 缓动动画,表单验证
//策略模式 示例:缓动动画//缓动效果策略族var tween = { linear: function ( t, b, c, d ) { return c*t /d +b; }, easyin: function ( t, b, c, d ) { return c* ( t /= d ) *t +b; }}//曲线策略族var path = { //beze:}var 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 ]; this.propertyName = propertyName; this.endPos = endPos; this.duration = duration; this.easing = tween[ easing ]; var self = this; var timeId = setInterval(function () { if ( self.step() == false ){ clearInterval(timeId); } },19);};Animate.prototype.step = function ( propertyName, endPos, duration, easing ) { var t = +new Date; if( t >= this.startTime + this.duration ){ this.update( this.endPos ); return false; } var 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';};var div = document.getElementById( 'xxx' );var animate = new Animate( div );animate.start('left', 500, 1000, 'easyin');
//策略模式 示例:表单校验/* @strategies 验证规则族*/var strategies = { isNotEmpty : function ( value, errMsg ) { if ( value === '' ){ return errMsg; } }, minLength: function ( value, length, errMsg ) { if( value.length < length ){ return errMsg; } }, maxLength: function ( value, length, errMsg ) { if( value.length > length ){ return errMsg; } }, isMobile: function ( value, errMsg ) { if( ! /(^1[3|5|8][0-9]{9}$)/ .test( value ) ){ return errMsg; } }};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 ary = rule.strategy.split( ':' ); var errorMsg = rule.errorMsg; self.cache.push(function () { var strategy = ary.shift(); ary.unshift( dom.value ); ary.push( errorMsg ); return strategies[ strategy ].apply( dom, ary ); }); })( rule ); }};Validator.prototype.start = function () { for( var i = 0, validataFunc; validataFunc = this.cache[ i++ ]; ){ var msg = validataFunc(); if( msg ){ return msg; } }};//表单校验使用场景/* @validataFunc 验证规则配置*/var xxxForm = document.getElementById( 'xxxForm' );var validataFunc = function () { var validator = new Validator(); //注册validator的验证规则 validator.add( xxxForm.userName, [ { strategy: 'isNotEmpty', errorMsg: '用户名不能为空' }, { strategy: 'minLength:6', errorMsg: '用户名长度不能小于6位' }, { strategy: 'maxLength:20', errorMsg: '用户名长度不能小于20位' } ] ); validator.add( xxxForm.password, [ { strategy: 'minLength:6', errorMsg: '密码长度不能少于6位' } ]); validator.add( xxxForm.phoneNumber, [ { strategy: 'isMobile', errorMsg: '手机号码格式不正确' } ]); var errMsg = validator.start(); return errMsg;};function check ( ) { }xxxForm.onsubmit= function () { var errorMsg = validataFunc(); if( errorMsg ){ //errorMsg不为空,表示验证不通过,阻止提交表单 //阻止提交表单的代码 alert( errorMsg ); return false; }};