设计模式之-策略模式

策略模式定义:

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

策略模式的组成:

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

相关推荐
老鼠只爱大米2 小时前
Java设计模式之代理模式(Proxy)深度解析
java·设计模式·代理模式·proxy pattern·java设计模式·proxypattern
老朱佩琪!3 小时前
Unity适配器模式
unity·设计模式·游戏引擎·适配器模式
vortex521 小时前
Bash Shell 的展开与补全机制
开发语言·bash
syt_101321 小时前
设计模式之-代理模式
设计模式·代理模式
拾忆,想起1 天前
设计模式:软件开发的可复用武功秘籍
开发语言·python·算法·微服务·设计模式·性能优化·服务发现
vortex51 天前
Bash 替换机制(三):变量替换
linux·开发语言·bash
加成BUFF1 天前
树莓派安装下载及远程连接(共用手机热点)(SSH)(VNC)
linux·计算机·ssh·bash·树莓派·vnc
vortex51 天前
Bash 替换机制(一):命令替换与进程替换
开发语言·chrome·bash
老朱佩琪!1 天前
Unity桥接模式
unity·设计模式·c#·桥接模式