设计模式之策略模式

本文介绍策略模式的概念及其在JavaScript中的实现,包括奖金计算示例及表单验证应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


目录

1.面向过程的最初代码

2.使用组合模式

3.使用传统策略模式重构代码

4.javascript版本的策略模式

5.表单校验

6.使用策略后的代码

7.给某个输入框添加多个校验规则   

8.最终效果 http://runjs.cn/code/d4okpeeh

1.面向过程的最初代码:

<script>
    var calculateBonus=function(performancelevel,salary){
        if(performancelevel==="s"){
            return salary*4;
        }
        if(performancelevel==="a"){
            return salary*3;
        }
        if(performancelevel==="b"){
            return salary*2;
        }
    };
    calculateBonus("b",2000);
    calculateBonus("s",6000);
</script>

缺点:

1.包含多个if-else,这些语句会影响其他逻辑分支

2.缺乏弹性操作,如果需要添加或替换策略需要修改函数内部,违反“开放-封闭”原则


2.使用组合模式:

<script>
    var s=function (salary){
        return salary*4;
    };
    var a=function (salary){
        return salary*3;
    };
    var b=function (salary){
        return salary*2;
    };
    var calculateBonus=function(performancelevel,salary){
        if(performancelevel==="s"){
            return s(salary);
        }
        if(performancelevel==="a"){
            return a(salary);
        }
        if(performancelevel==="b"){
            return b(salary);
        }
    };
    calculateBonus("s",300000);
</script>
在最初代码基础上进行了改善,单还未解决最初代码的缺陷


3.使用传统策略模式重构代码:

<script>
    //定义多个策略类------------
    var performanceS=function(){};
    performanceS.prototype.calculate=function(salary){
        return salary*4;
    };
    var performanceB=function(){};
    performanceB.prototype.calculate=function(salary){
        return salary*2;
    };
    var performanceA=function(){};
    performanceA.prototype.calculate=function(salary){
        return salary*3;
    };
    //定义奖金类-------------------
    var Bonus=function(){
        this.salary=null;//原始工资
        this.strategy=null;//定义对应策略对象
    };
    //设置员工原始工资
    Bonus.prototype.setSalary=function(salary){
        this.salary=salary;
    };
    //设置员工绩效对应的策略对象
    Bonus.prototype.setStrategy=function(strategy){
        this.strategy=strategy;
    };
    //获取奖金金额
    Bonus.prototype.getBonus=function(){
        return this.strategy.calculate(this.salary)
    };
    //使用--------------------------
    var bonus=new Bonus();
    bonus.setSalary(1000);
    bonus.setStrategy(new performanceA());//设置策略对象
    console.log(bonus.getBonus());
</script>

策略模式:

至少包含两部分---

1.策略类  --封装了具体的算法,并负责计算过程,可以划分为两部分【规则和使用规则】

 2.环境类----接受客户的请求,并随后委托给一个策略类


4.javascript版本的策略模式:

<script>
    /*
    * 在javascript中函数也是对象,所以javascript中的直接把strategy定义为一个策略集合对象*/
    //策略对象
    var strategies={
        "s":function(salary){
            return salary*4;
        },
        "a":function(salary){
            return salary*3;
        },
        "b":function(salary){
            return salary*2;
        }
    };
    //代替传统策略模式里面的Bonus类,和命令模式的安装命令工具一样功能
    var calculateBonus=function(level,salary){
        return strategies[level](salary);
    };
    console.log(calculateBonus("s",20000));//80000
    console.log(calculateBonus("a",10000));//30000
</script>

在javascript中,函数也是对象,所以简单直接的吧strategy直接定义为一个包含策略集合的函数,context也没必要用bonus类来表示,这样代码更加简洁


5.表单校验

常见代码:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<form action="http://www.baidu.com" id="registerForm">
    <div>
        请输入用户名:<input type="text" name="userName"/>
    </div>
    <div>
        请输入密码:<input type="text" name="password"/>
    </div>
    <div>
        请输入手机号:<input type="text" name="phoneNumber"/>
    </div>
    <div>
        <button>提交</button>
    </div>
</form>
<script>
    var registerForm=document.getElementById("registerForm");
    registerForm.onsubmit=function(){
        if(registerForm.userName.value==""){
            alert("用户名不能为空");
            return false;
        }
        if(registerForm.password.value.length<6){
            alert("密码不能少于6位");
            return false;
        }
        if(!/^[1][358][0-9]{9}$/.test(registerForm.phoneNumber.value)){
            alert("手机号码不正确");
            return false;
        }
    }

</script>
</body>
</html>

6.使用策略后的代码:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<form  id="registerForm">
    <div>
        请输入用户名:<input type="text" name="userName"/>
    </div>
    <div>
        请输入密码:<input type="text" name="password"/>
    </div>
    <div>
        请输入手机号:<input type="text" name="phoneNumber"/>
    </div>
    <div>
        <button>提交</button>
    </div>
</form>
<script>
    var registerForm=document.getElementById("registerForm");
    //定义策略类
    var strategies={
        isNonEmpty:function(value,errorMsg){
            if(value===""){
                console.log(this);//这里的this指向dom
                return errorMsg;
            }
        },
        minLength:function(value,length,errorMsg){
            if(value.length<length){
                return errorMsg;
            }
        },
        isMobile:function(value,errorMsg){
            if(!/^[1][358][0-9]{9}$/.test(registerForm.phoneNumber.value)){
                return errorMsg;
            }
        }
    };
//定义Validator类----------------------
    var Validator=function(){
        this.cache=[];//保存校验规则
    };
    Validator.prototype.add=function(dom,rule,errorMsg){
        var ary=rule.split(":");
        this.cache.push(function(){
            var strategy=ary.shift();//规则名
            ary.unshift(dom.value);//dom的value
            ary.push(errorMsg);//错误提示
            console.log(ary);
            //最终ary格式为["input的value","提示"]
            return strategies[strategy].apply(dom,ary);//把策略模式在dom环境内运行
        })
    };
    Validator.prototype.start=function(){
        for(var i= 0,validatorFunc;validatorFunc=this.cache[i++];){
            var msg=validatorFunc();//开始验证后返回信息
            if(msg){
                return msg;
            }
        }
    };
    //用户提交表单验证请求-------------
var validataFunc=function(){
    var validator=new Validator();//创建一个对象
    validator.add(registerForm.userName,"isNonEmpty","用户名不能为空");
    validator.add(registerForm.password,"minLength:6","密码长度不能少于6");
    validator.add(registerForm.phoneNumber,"isMobile","手机号格式不对");

    var errorMsg=validator.start();//获取校验结果
    return errorMsg;
};
    registerForm.onsubmit=function(){
        var errorMsg=validataFunc();//如果放回true说明为未通过校验
        if(errorMsg){
            alert(errorMsg);
            return false;
        }


    }
</script>
</body>
</html>


7.给某个输入框添加多个校验规则:

例如我们想校验它即不能为空同时限制长度为10,我们期待以这种格式进行校验:

validator.add(registerForm.userName,[{
    strategy:"isNonEmpty",
    errorMsg:"用户名不能为空"
},{
    strategy:"minLength:6",
    errorMsg:"用户名不能长度不能小于6"
}]);

我们只需要给原来的add方法里面添加个for就能实现了具体javascript代码如下:

<script>
    /***********************策略************************/
    //定义策略类
    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][358][0-9]{9}$/.test(registerForm.phoneNumber.value)){
                return errorMsg;
            }
        }
    };
    /***********************validator类************************/
    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(":");
                console.log(ary);//如果格式为"minLength:6"这样的将会给策略传入多一个参数6
                var errorMsg=rule.errorMsg;
                self.cache.push(function(){
                    var strategy=ary.shift();//规则名
                    ary.unshift(dom.value);//dom的value
                    ary.push(errorMsg);//错误提示
                    console.log(ary);
                    //最终ary格式为["input的value","提示"]
                    return strategies[strategy].apply(dom,ary);//把策略模式在dom环境内运行
                })
            })(rule)
        }
    };
    Validator.prototype.start=function(){
        for(var i= 0,validatorFunc;validatorFunc=this.cache[i++];){
            var msg=validatorFunc();//开始验证后返回信息
            if(msg){
                return msg;
            }
        }
    };
    /*客户调用代码*/
    var registerForm=document.getElementById("registerForm");
    var validataFunc=function(){
        var validator=new Validator();

        validator.add(registerForm.userName,[{
            strategy:"isNonEmpty",
            errorMsg:"用户名不能为空"
        },{
            strategy:"minLength:6",
            errorMsg:"用户名不能长度不能小于6"
        }]);
        validator.add(registerForm.password,[{
            strategy:"minLength:6",
            errorMsg:"密码长度不能小于6"
        }]);
        validator.add(registerForm.phoneNumber,[{
            strategy:"isMobile",
            errorMsg:"密码长度不能小于6"
        }]);
        var errorMsg=validator.start();
        return errorMsg;
    };
    registerForm.onsubmit=function(){
        var errorMsg=validataFunc();
        if(errorMsg){
            alert(errorMsg);
                return false;
            }

    }
</script>

8.最终效果:http://runjs.cn/code/d4okpeeh

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆康永

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值