• 设计模式之策略模式


    一、是什么

    策略模式(Strategy Pattern)指的是定义一系列的算法,把它们一个个封装起来,目的就是将算法的使用与算法的实现分离开来

    一个基于策略模式的程序至少由两部分组成:

    • 策略类,策略类封装了具体的算法,并负责具体的计算过程
    • 环境类Context,Context 接受客户的请求,随后 把请求委托给某一个策略类

    二、使用

    举个例子,公司的年终奖是根据员工的工资和绩效来考核的,绩效为A的人,年终奖为工资的4倍,绩效为B的人,年终奖为工资的3倍,绩效为C的人,年终奖为工资的2倍

    若使用if来实现,代码则如下:

    1. var calculateBouns = function(salary,level) {
    2. if(level === 'A') {
    3. return salary * 4;
    4. }
    5. if(level === 'B') {
    6. return salary * 3;
    7. }
    8. if(level === 'C') {
    9. return salary * 2;
    10. }
    11. };
    12. // 调用如下:
    13. console.log(calculateBouns(4000,'A')); // 16000
    14. console.log(calculateBouns(2500,'B')); // 7500

    从上述可有看到,函数内部包含过多if...else,并且后续改正的时候,需要在函数内部添加逻辑,违反了开放封闭原则

    而如果使用策略模式,就是先定义一系列算法,把它们一个个封装起来,将不变的部分和变化的部分隔开,如下:

    1. var obj = {
    2. "A": function(salary) {
    3. return salary * 4;
    4. },
    5. "B" : function(salary) {
    6. return salary * 3;
    7. },
    8. "C" : function(salary) {
    9. return salary * 2;
    10. }
    11. };
    12. var calculateBouns =function(level,salary) {
    13. return obj[level](salary);
    14. };
    15. console.log(calculateBouns('A',10000)); // 40000

    上述代码中,obj对应的是策略类,而calculateBouns对应上下通信类

    又比如实现一个表单校验的代码,常常会像如下写法:

    1. var registerForm = document.getElementById("registerForm");
    2. registerForm.onsubmit = function(){
    3. if(registerForm.userName.value === '') {
    4. alert('用户名不能为空');
    5. return;
    6. }
    7. if(registerForm.password.value.length < 6) {
    8. alert("密码的长度不能小于6位");
    9. return;
    10. }
    11. if(!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {
    12. alert("手机号码格式不正确");
    13. return;
    14. }
    15. }

    上述代码包含多处if语句,并且违反了开放封闭原则,如果应用中还有其他的表单,需要重复编写代码

    此处也可以使用策略模式进行重构校验,第一步确定不变的内容,即策略规则对象,如下:

    1. var strategy = {
    2. isNotEmpty: function(value,errorMsg) {
    3. if(value === '') {
    4. return errorMsg;
    5. }
    6. },
    7. // 限制最小长度
    8. minLength: function(value,length,errorMsg) {
    9. if(value.length < length) {
    10. return errorMsg;
    11. }
    12. },
    13. // 手机号码格式
    14. mobileFormat: function(value,errorMsg) {
    15. if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
    16. return errorMsg;
    17. }
    18. }
    19. };

    然后找出变的地方,作为环境类context,负责接收用户的要求并委托给策略规则对象,如下Validator类:

    1. var Validator = function(){
    2. this.cache = []; // 保存效验规则
    3. };
    4. Validator.prototype.add = function(dom,rule,errorMsg) {
    5. var str = rule.split(":");
    6. this.cache.push(function(){
    7. // str 返回的是 minLength:6
    8. var strategy = str.shift();
    9. str.unshift(dom.value); //inputvalue添加进参数列表
    10. str.push(errorMsg); // 把errorMsg添加进参数列表
    11. return strategys[strategy].apply(dom,str);
    12. });
    13. };
    14. Validator.prototype.start = function(){
    15. for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {
    16. var msg = validatorFunc(); // 开始效验 并取得效验后的返回信息
    17. if(msg) {
    18. return msg;
    19. }
    20. }
    21. };

    通过validator.add方法添加校验规则和错误信息提示,使用如下:

    1. var validateFunc = function(){
    2. var validator = new Validator(); // 创建一个Validator对象
    3. /* 添加一些效验规则 */
    4. validator.add(registerForm.userName,'isNotEmpty','用户名不能为空');
    5. validator.add(registerForm.password,'minLength:6','密码长度不能小于6位');
    6. validator.add(registerForm.userName,'mobileFormat','手机号码格式不正确');
    7. var errorMsg = validator.start(); // 获得效验结果
    8. return errorMsg; // 返回效验结果
    9. };
    10. var registerForm = document.getElementById("registerForm");
    11. registerForm.onsubmit = function(){
    12. var errorMsg = validateFunc();
    13. if(errorMsg){
    14. alert(errorMsg);
    15. return false;
    16. }
    17. }

    上述通过策略模式完成表单的验证,并且可以随时调用,在修改表单验证规则的时候,也非常方便,通过传递参数即可调用

    三、应用场景

    从上面可以看到,使用策略模式的优点有如下:

    • 策略模式利用组合,委托等技术和思想,有效的避免很多if条件语句
    • 策略模式提供了开放-封闭原则,使代码更容易理解和扩展
    • 策略模式中的代码可以复用

    策略模式不仅仅用来封装算法,在实际开发中,通常会把算法的含义扩散开来,使策略模式也可以用来封装 一系列的“业务规则”

    只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以用策略模式来封装它们

  • 相关阅读:
    Proteus仿真--12864LCD显示计算器键盘按键实验(仿真文件+程序)
    当zk某个节点坏掉如何修复
    Postman —— postman的介绍和安装
    torchvision中的标准ResNet50网络结构
    docker基础知识
    【面试宝典】Java八股文之Redis面试题
    Mybatis-Plus——分页+模糊查询
    10.Java集合汇总
    java冒泡排序
    编程可以自学吗
  • 原文地址:https://blog.csdn.net/Ming_xm/article/details/134304628