策略模式定义:
策略模式定义了一系列的算法,并且会将每一个算法封装起来,让它们可以相互的替换。
策略模式的组成:
一个基于策略模式的程序至少由两部分组成,第一部分是一组策略类,策略类封装了具体的算法,并负责具体计算过程,第二个部分是环境类Context,Context接受客户的请求,随后把请求委托给某一个策略类,说明Context中要维护对某个策略对象的引用
typescript
// 策略接口
interface IStrategy {
execute(a:number,b:number):number;
}
// 定义具体的策略类
// 这里定义了四个具体的策略类,分别是加法、减法、乘法和除法
class AddStrategy implements IStrategy {
execute(a: number, b: number): number {
return a+b;
}
}
class SubStrategy implements IStrategy {
execute(a: number, b: number): number {
return a-b;
}
}
class MulStrategy implements IStrategy {
execute(a: number, b: number): number {
return a*b;
}
}
class DivStrategy implements IStrategy {
execute(a: number, b: number): number {
return a/b;
}
}
// 上下文内部维护了具体的策略的引用
// 回头客户端调用的时候,只需要调用上下文的方法即可
class Context {
// 维护具体的策略
private strategy:IStrategy;
constructor(st:IStrategy){
this.strategy = st;
}
// 设置新的策略
setStrategy(st:IStrategy){
this.strategy = st;
}
//执行策略方法
executeStrategy(a:number,b:number):number{
return this.strategy.execute(a,b);
}
}
// 创建一个上下文对象
// 在创建的时候,传递一个默认的执行策略
const context = new Context(new AddStrategy());
// 执行对应的策略
const a=5;
const b=3;
const result = context.executeStrategy(a,b);
context.setStrategy(new SubStrategy())
const result2 = context.executeStrategy(a,b);
context.setStrategy(new MulStrategy());
const result3 = context.executeStrategy(a,b);
console.log(result);
console.log(result2);
console.log(result3);
再来看一个表单的例子
xml
<form id="registerForm" action="#">
请输入用户名:<input type="text" name="username" />
请输入密码:<input type="text" name="password" />
请输入手机号:<input type="text" name="phoneNumber" />
<button id="button">提交</button>
</form>
<script>
var registerForm=document.getElementById('registerForm');
var button=document.getElementById('button');
button.onclick = function(){
if(registerForm.username.value===''){
console.log('用户名不能为空');
return false
}
if(registerForm.password.value.length<6){
console.log('密码长度不能少于6位');
return false
}
if(!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)){
console.log('手机号码格式不正确');
return false
}
}
</script>
这是一种很常见的做法,提交函数比较庞大,缺少弹性,违反开放-封闭原则
下面用策略模式来重构表单校验
javascript
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;
}
}
}
var validataFunc = function(){
var validator=new Validator(); // 创建一个validator对象
// 添加一些校验规则
validator.add(registerForm.username,'isNonEmpty','用户名不能为空');
validator.add(registerForm.password,'minLength:6','密码长度不能少于6位');
validator.add(registerForm.phoneNumber,'isMobile','手机号码格式不正确');
var errorMsg=validator.start(); // 获得校验结果
return errorMsg; // 返回校验结果
}
var registerForm=document.getElementById('registerForm');
var button=document.getElementById('button');
button.onclick = function(e){
e.preventDefault();
var errorMsg = validataFunc(); // 如果有返回值,说明未通过校验
if(errorMsg){
console.log(errorMsg);
return false;
}
}
var Validator = function(){
this.cache=[];// 保存校验规则
}
Validator.prototype.add = function(dom,rule,erroeMsg){
var arg = rule.split(':'); // 把strategy和参数分开
this.cache.push(function(){ // 把校验的步骤用空函数包装起来,并且放入cache
var strategy=arg.shift(); // 用户挑选的strategy
arg.unshift(dom.value);
arg.push(erroeMsg);
return strategies[strategy].apply(dom,arg);
})
}
Validator.prototype.start=function(){
for(let i=0,validataFunc;validataFunc=this.cache[i++];){
var msg=validataFunc(); // 开始校验,并取得校验后返回信息
if(msg){ // 有返回值,说明校验没有通过
return msg;
}
}
}
非原创,来源渡一谢杰老师和javascript设计模式与开发实践 -曾探 简单记录,周五啦,周末愉快