Skip to content

策略模式 #17

Open
Open
@isNeilLin

Description

@isNeilLin

策略模式

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

并且使它们可以相互替换”,这句话在很大程度上是相对于静态类型语言而言的。因为静态类型语言中有类型检查机制,所以各个策略类需要实现同样的接口。当它们的真正类型被隐藏在接口后面时,它们才能被相互替换。而在JavaScript这种“类型模糊”的语言中没有这种困扰,任何对象都可以被替换使用。因此,JavaScript中的“可以相互替换使用”表现为它们具有相同的目标和意图。

策略模式的目的就是将算法的使用与算法的实现分离开来。

一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。 第二个部分是环境类Context,Context接受客户的请求,随后把请求委托给某一个策略类。要做到这点,说明Context中要维持对某个策略对象的引用

// JavaScript版本的策略模式
var strategies = {
	'S': function(salary){
		return salary * 4;
	},
	'A': function(salary){
		return salary * 3;
	},
	'B': function(salary){
		return salary * 2;
	}
}

var calculate = function(level, salary){
	return strategies[level](salary);
}

缓动动画

/*
	@param {
		t: 动画已消耗的时间,
		b: 小球原始位置,
		c: 小球目标位置,
		d: 动画持续的总时间
	}
*/
var tween = {
	linear: function(t, b, c, d){
		return c*t/d + b;
	},
	easeIn: function(t, b, c, d){
		return c * ( t /= d # 策略模式

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

> 并且使它们可以相互替换”,这句话在很大程度上是相对于静态类型语言而言的。因为静态类型语言中有类型检查机制,所以各个策略类需要实现同样的接口。当它们的真正类型被隐藏在接口后面时,它们才能被相互替换。而在JavaScript这种“类型模糊”的语言中没有这种困扰,任何对象都可以被替换使用。因此,JavaScript中的“可以相互替换使用”表现为它们具有相同的目标和意图。

策略模式的目的就是将算法的使用与算法的实现分离开来。

一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。 第二个部分是环境类Context,Context接受客户的请求,随后把请求委托给某一个策略类。要做到这点,说明Context中要维持对某个策略对象的引用

```javascript
// JavaScript版本的策略模式
var strategies = {
	'S': function(salary){
		return salary * 4;
	},
	'A': function(salary){
		return salary * 3;
	},
	'B': function(salary){
		return salary * 2;
	}
}

var calculate = function(level, salary){
	return strategies[level](salary);
}

缓动动画

/*
	@param {
		t: 动画已消耗的时间,
		b: 小球原始位置,
		c: 小球目标位置,
		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;
	this.startTime = 0;
	this.startPos = 0;
	this.endPos = 0;
	this.easing = null;
	this.duration = null;
	this.prototyName = null;
}

Animate.prototype.start = function(prototyName,endPos,duration,easing){
	this.startTime = +new Date;
	this.startPos = this.dom.getBoundingClientRect()[prototyName];
	this.prototyName = prototyName;
	this.endPos = endPos;
	this.duration = duration;
	this.easing = tween[easing]; // 缓动算法
	var self = this;
	var timeId = setInterval(function(){
		if(self.step()===false){
			clearInterval(timeId);
		}
	})
}

Animate.prototype.step = function(){
	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.prototyName] = pos + 'px';
}

var div = document.getElementById( 'div' );
var animate = new Animate( div );

animate.start( 'left', 500, 1000, 'strongEaseOut' );

表单验证

<body>
	<form id="registerForm">
		请输入用户名:<input type="text" name="userName"/ >
		<br>
        请输入密码:<input type="text" name="password"/ >
        <br>
        请输入手机号码:<input type="text" name="phoneNumber"/ >
        <br>
        <button>提交</button>
	</form>
<script type="text/javascript">
	// 表单校验
	var strategies = {
		isEmpty: function(val,errormsg){
			if(val===''){
				return errormsg;
			}
		},
		minLength: function(val,length,errormsg){
			if(val.length < length){
				return errormsg;
			}
		},
		isMobile: function(val,errormsg){
			if(!/(^1[3|5|8][0-9]{9}$)/.test(val)){
				return errormsg;
			}
		}
	}

	var Validator = function(){
		this.cache = [];
	}
	Validator.prototype.add = function(dom, rule, msg){
		var ary;
		if(arguments.length===3){
			ary = rule.split(':');
			var strategy = strategies[ary.shift()];
			ary.unshift(dom.value);
			ary.push(msg);
			this.cache.push(function(){
				return strategy.apply(this,ary);
			})
		}else if(arguments.length===2&&(Object.prototype.toString.call(rule)==='[object Array]')){
			rule.map(ruleObj=>{
				this.add(dom,ruleObj.strategy,ruleObj.errormsg);
			})
		}
	}

	Validator.prototype.start = function(){
		for(var i=0, func;func = this.cache[i++]; ){
			var msg = func();
			if(msg){
				return msg;
			}
		}
	}

	var ValidatorFuc = function(){
		var validator = new Validator();
		validator.add(registerForm.userName,[
		{
			strategy: 'isEmpty',
			errormsg: '用户名不能为空'
		},
		{
			strategy: 'minLength:8',
			errormsg: '用户名长度不能少于8位'
		}
		]);
		validator.add(registerForm.password,'minLength:6','密码长度不能少于6位');
		validator.add(registerForm.userName,'isMobile','手机号格式不正确');
		var errormsg = validator.start();
		return errormsg;
	}

	document.getElementById('registerForm').onsubmit = function(e){
		e.preventDefault();
		var errorMsg = ValidatorFuc();   // 如果errorMsg有确切的返回值,说明未通过校验
	     if ( errorMsg ){
	         alert ( errorMsg );
	         return false;    // 阻止表单提交
	     }
	}
</script>

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions