设计模式之-策略模式

策略模式定义:

策略模式定义了一系列的算法,并且会将每一个算法封装起来,让它们可以相互的替换。

策略模式的组成:

一个基于策略模式的程序至少由两部分组成,第一部分是一组策略类,策略类封装了具体的算法,并负责具体计算过程,第二个部分是环境类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设计模式与开发实践 -曾探 简单记录,周五啦,周末愉快

相关推荐
触底反弹9 分钟前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试
张小姐的猫18 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
杨充20 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充21 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充21 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充21 小时前
2.面向对象的特性
设计模式
杨充21 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充21 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充21 小时前
3.接口vs抽象类比较
设计模式