• 策略模式,一种广泛应用于各种情况的设计模式(设计模式与开发实践 P5)


    策略模式

    定义:定义一系列算法,把它们一个个封装起来,并且可以互相替换

    例如,我们要计算年终奖,年终奖根据绩效 A、B、C 来计算最终数值

    实现

    最初我们很容易想到用 分支 if 来解决这个问题,如果绩效 = A 则工资 x 2,如果绩效 = B 则工资 x 3

    如果经常使用这样的分支结构,你会发现代码耦合度很高,很容易就出现一大坨代码堆砌在一起,只是 x 2 或者 x 3 不足以形成难以维护的结构,但如果不是 x 2 而是一个复杂的代码块,我们显然会想到封装里面的代码!

    var performA = function (salary) {
      return salary * 4;
    };
    
    var performB = function (salary) {
      return salary * 3;
    };
    
    var performC = function (salary) {
      return salary * 2;
    };
    
    var calcBonus = function (level, salary) {
      if (level == "A") {
        return performA(salary);
      } else if (level == "B") {
        return performB(salary);
      } else if (level == "C") {
        return performC(salary);
      }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    是的,虽然我们优化了代码,但没好到哪去,如果要添加一个 D 级,我们还是得堆砌代码

    让我们来看看策略模式怎么做吧,策略模式让 策略 被定义和封装,且可以相互替换

    这就是最终代码了,但在 javascript 中实现策略相较 C# 或者其他语言来说要容易的多,在下面举例了 C# 代码

    var strategies = {
      A: function (salary) {
        return salary * 4;
      },
      B: function (salary) {
        return salary * 3;
      },
      C: function (salary) {
        return salary * 2;
      },
    };
    
    var calculateBonus = function (level, salary) {
      return strategies[level](salary);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    需要注意的是 strategies 对象存储的 3 个匿名函数, Func 类是用来存储函数的,需要一定的函数工具类基础

    掌握这样的思想以后,试着把 {"A", (salary) => salary * 4} 解耦出去动态添加即可~

    using System;
    using System.Collections.Generic;
    
    public class Program
    {
        private static Dictionary<string, Func<double, double>> strategies = new Dictionary<string, Func<double, double>>()
        {
            {"A", (salary) => salary * 4},
            {"B", (salary) => salary * 3},
            {"C", (salary) => salary * 2}
        };
    
        private static double CalculateBonus(string level, double salary)
        {
            return strategies[level](salary);
        }
    
        public static void Main(string[] args)
        {
            string level = "A";
            double salary = 1000;
    
            double bonus = CalculateBonus(level, salary);
            Console.WriteLine("Bonus: " + bonus);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    思想

    通过上面的重构:

    • 消除了大片的分支语句
    • 计算奖金的逻辑不再存储在 CalculateBonus 里了,而是分布在策略对象里
    • 策略对象只负责计算奖金
    • 策略对象之间可以相互替换

    实战 - 表单

    这是一种尤为常见的表单验证方式,相信绝大多数前端程序员这样写过

    显然能发现,这里的 if 堆砌过多,不仅如此,内部的 逻辑 相比上面的代码也更复杂

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

    我们可以用策略模式的思路来实现类似这样的代码,这样当我们需要增加验证步骤时,只需要添加策略内容即可:

    var validateStrategy = {
      isNotEmpty: function (form) {
        if (form.name === "") {
          return "用户名不能为空";
        }
        return "";
      },
      minLength: function (form) {
        if (form.password.length < 6) {
          return "密码长度不能少于6位";
        }
        return "";
      },
      isMobile: function (form) {
        if (!/(^1[3|5|8][0-9]{9}$)/.test(form.phone)) {
          return "手机号码格式不正确";
        }
        return "";
      },
    };
    
    var validate = function (form) {
      for (let func in validateStrategy) {
        if (
          validateStrategy.hasOwnProperty(func) &&
          typeof validateStrategy[func] === "function"
        ) {
          var msg = validateStrategy[func](form);
          if (msg != "") return false;
        }
      }
      return true;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
  • 相关阅读:
    Xubuntu16.04系统中解决无法识别exFAT格式的U盘
    【区块链实战】什么是DAPP,区块链开发如何进行技术选型
    Hbase简介
    Go-知识error
    linux中crontab讲解
    机器学习西瓜书+南瓜书吃瓜教程学习笔记第五章神经网络
    vue项目查看vue版本-- 踩坑
    图片怎么改成jpg格式
    如何在 vue3 中使用 jsx/tsx?
    基于BP/RBF神经网络的在线信道估计均衡算法matlab仿真
  • 原文地址:https://blog.csdn.net/Littlelumos/article/details/132913793