类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式
策略模式中, 创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法
策略模式的优点
- 算法(功能)可以自由切换
- 避免使用多重条件判断
- 扩展性好
策略模式的缺点
- 策略类会增多
- 所有的策略都会暴露在外部
代码
这里是按照超市支付的角色为模型创建,有四个策略,普通顾客,熟客,会员,老板等,在支付的时候使用不同的策略
- 策略内置实现
class Customer{
// 第一策略
kinds = {
// 普通用户
normal: {
pay(amount) {
return amount
}
},
// 会员
member: {
pay(amount) {
return amount * .9
}
},
// VIP
vip: {
pay(amount) {
return amount * .8
}
}
}
/**
* @des 暴露扩展策略接口
* @param { Sting } kind 策略类型的名字
* @param { Object } obj 策略对象
*/
addKind(kind, obj) {
this.kinds[kind] = obj
}
// 统一暴露的支付方法
pay(kind, amount) {
return this.kinds[kind].pay(amount)
}
}
// 调用
let c = new Customer()
// 使用普通支付
console.log(c.pay('normal', 100))
// 使用会员支付
console.log(c.pay('member', 100))
// 使用VIP身份支付
console.log(c.pay('vip', 100))
// 新增老板模式
c.addKind('boss', {
pay(amount) {
return 0
}
})
// 使用老板模式i支付
console.log(c.pay('boss', 100))
- 策略外置实现
// 策略外置写法
class Customer {
constructor(Kind) {
this.kind = new Kind()
}
// 对外暴露方法
pay(amount) {
return this.kind.pay(amount)
}
}
// 定义策略
class Normal{
pay(amount) {
return amount
}
}
class Member{
pay(amount) {
return amount * .9
}
}
class VIP{
pay(amount) {
return amount * .8
}
}
class Boss{
pay(amount) {
return 0
}
}
// 普通会员
let c1 = new Customer(Normal)
console.log(c1.pay(100))
// 会员
let c2 = new Customer(Member)
console.log(c2.pay(100))
// vip
let c3 = new Customer(VIP)
console.log(c3.pay(100))
// Boss
let c4 = new Customer(Boss)
console.log(c4.pay(100))
使用场景
-
表单验证
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <title>策略模式之表单验证</title> <style> .container{ padding-top: 200px; } .line{ margin-bottom: 12px; } </style> </head> <body> <div class="container"> <form id="form"> <div class="line"> 账 号: <input type="text" name="name" id="name"> </div> <div class="line"> 密 码: <input type="password" name="password" id="password"> </div> <div class="line"> 验证码: <input type="vertiry" name="vertiry" id="vertiry"> </div> <div class='line'> <button type="button" class="btn btn-primary" id="submit">提交</button> </div> </form> </div> <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) --> <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script> <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> <script> class Validate { roules = { empty: (val, msg) => { // 判断是否为空 if (!val) return msg }, minLength: (val, len, msg) => { // 检查对小长度 if (!val || val.length < len) return msg }, maxLength: (val, len, msg) => { // 检查最大长度 if (!val || val.length > len) return msg }, isNumber: (val, msg) => { // 判断是否为纯数字 let reg = /^[0-9]*$/g; if (!reg.test(val)) return msg } } // 检测函数回调 callbacks = [] // 添加函数 add(el, val) { this.callbacks.push(() => { let key = val[0] let value = el.value return this.roules[key].apply(this, [value, ...val.slice(1)]) }) } /** * @desc 添加规则 * */ addRoule(roule, fn) { this.roules[roule] = fn } /** * @desc 验证 * */ vertify() { let msg = '' let { callbacks } = this for (let i = 0, len = callbacks.length; i < len; i++) { let fn = callbacks[i] msg = fn() // 如果有msg 说明校验不通过 if (msg) { return msg } } } } // 添加长度等于规则 let form = document.querySelector('#form') let btn = document.querySelector('#submit') let validate = new Validate() validate.addRoule('equlLength', (val, len, msg) => { if (!val || val.length !== len) return msg }) // 添加验证规则 validate.add(form.name, ['empty', '用户名不能为空']) validate.add(form.password, ['empty', '密码不能为空']) validate.add(form.password, ['minLength', 6, '密码不能少于6位']) validate.add(form.password, ['maxLength', 8, '密码不能大于8位']) validate.add(form.vertiry, ['empty', '验证码不能为空']) validate.add(form.vertiry, ['isNumber', '验证码必须为数字']) validate.add(form.vertiry, ['equlLength', 4, '验证码为4为数字']) btn.addEventListener('click', () => { let res = validate.vertify() if (res) { alert(res) return false } }) </script> </body> </html>