设计模式(11) 策略模式

策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

介绍

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

主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。

如何解决:将这些算法封装成一个一个的类,任意地替换。

关键代码:实现同一个接口。

应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。

优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

实现

1,打折优惠

class Customer {
    constructor() {
        this.kinds = {
            normal: function(amount) {
                return amount;
            },
            member: function(amount) {
                return amount*.9;
            },
            vip: function(amount) {
                return amount*.8;
            }
        }
    }
    pay(kind,amount) {
        return this.kinds[kind](amount);
    } 
}

let c = new Customer();
console.log(c.pay('vip',100));

2,表单验证

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <form id="userForm">
      用户名: <input type="text" name="username" /> 密码:<input
        type="text"
        name="password"
      />
      手机号: <input type="text" name="mobile" />
      邮箱: <input type="text" name="email" />
      <input type="submit" value="提交" />
    </form>
  </body>
  <script>
    let form = document.getElementById("userForm");
    let validator = (function () {
      let rules = {
        notEmpty(val, msg) {
          if (val === "") {
            return msg;
          }
        },
        minLength(val, min, msg) {
          if (val === "" || val.length < min) {
            return msg;
          }
        },
        maxLength(val, max, msg) {
          if (val === "" || val.length > max) {
            return msg;
          }
        },
        isMobile(val, msg) {
          if (!/1\d{10}/.test(val)) {
            return msg;
          }
        },
      };

      let checks = [];
      //增加校验的项目
      function add(element, rule) {
        let val = element.value;
        checks.push(() => {
          return rules[rule[0]](val, ...rule.slice(1));
        });
      }

      function start() {
        let msg = "";
        checks.forEach((fn) => {
          if (!msg) {
            msg = fn();
          }
        });
        checks = [];
        return msg;
      }
      function addRule(name,rule) {
        rules[name] = rule;
      }
      return {
        add,
        start,
        addRule
      };
    })();
    validator.addRule('email',function(val,msg) {
      if(!/.*@.*/.test(val)) {
        return msg;
      }
    })
    form.onsubmit = function () {
      validator.add(form.username, ["notEmpty", "用户名不能为空"]);
      validator.add(form.password, ["minLength", 6, "密码长度不能少于6位"]);
      validator.add(form.password, ["maxLength", 8, "密码长度不能大于8位"]);
      validator.add(form.mobile, ["isMobile", "必须输入合法的手机号"]);
      validator.add(form.email,['email','邮箱格式不对']);
      let msg = validator.start();
      if (msg) {
        alert(msg);
        return false;
      }
    };
  </script>
</html>
正文到此结束
评论插件初始化中...
Loading...