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

文章目录

策略模式

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

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

实现

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

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

javascript 复制代码
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);
  }
};

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

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

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

javascript 复制代码
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);
};

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

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

csharp 复制代码
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);
    }
}

思想

通过上面的重构:

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

实战 - 表单

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

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

javascript 复制代码
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;
  }
};

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

javascript 复制代码
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;
};
相关推荐
折哥的程序人生 · 物流技术专研2 小时前
【电商多平台电子面单对接实战|第二篇】抖音代发电子面单对接:从“面条代码”到整洁架构的涅槃之路
设计模式·架构·系统架构·单元测试·代码规范·单一职责原则
葫芦和十三3 小时前
范式之变|Agent 设计,换语言了
人工智能·设计模式
ourenjiang3 小时前
【学习设计模式】原型模式
学习·设计模式·原型模式
贵慜_Derek4 小时前
《从零实现 Agent 系统》连载 20|MCP 与 Code Execution:协议、档位与 Sidecar
人工智能·设计模式·架构
Dr_eamboat17 小时前
SpringBoot策略模式+工厂模式实战解析
linux·spring boot·策略模式
Sam_Deep_Thinking1 天前
结算分摊的策略模式:不同营销活动的扣点计算方案
java·设计模式·架构·系统架构
故渊at1 天前
系列一:架构思想进阶 | 第3篇 SOLID 原则与设计模式实战:从“代码搬运工”到“架构师”的必经之路
观察者模式·设计模式·重构·架构·代理模式
老码观察2 天前
设计模式实战解读(十一):外观模式——给复杂系统套一层壳
python·设计模式·外观模式
AI大法师2 天前
奥迪 AUDI 案例:母品牌和新业务怎么拆?
大数据·设计模式·汽车