策略模式,一种广泛应用于各种情况的设计模式(设计模式与开发实践 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);
  }
};

是的,虽然我们优化了代码,但没好到哪去,如果要添加一个 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);
};

需要注意的是 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);
    }
}

思想

通过上面的重构:

  • 消除了大片的分支语句
  • 计算奖金的逻辑不再存储在 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;
  }
};

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

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;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值