javascript 设计模式 - 策略模式

内容大部分来自 《javascript 设计模式与开发实践》一书,适当的结合自己工作实践,做出整理和笔记
系列: javascript 设计模式

策略模式

策略模式定义为定义一些列的算法,把他们一个一个封装起来,并且可以相互替换

  • 分离变化和不变是每个设计模式的主题,策略模式也不例外
  • 策略模式封装的算法,实际使用中算法也可能是相同的 业务规则业务规则 目标一致,并且可以替换使用,就可以封装它们

基本实现

例:不同绩效等级的人对应不同的绩效奖金算法,通过抽离不同的奖金算法为策略,把请求委托给策略对象的某个方法进行计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 计算奖金的策略
const aonusStrategys = {
A(salary) {
return salary * 5;
},
B(salary) {
return salary * 2;
},
C(salary) {
return salary * 1;
},
D(salary) {
return 0;
}
}

const calculateBonus = (level, salary) => {
return aonusStrategys[level](salary);
};

console.log(`calculateBonus A:${calculateBonus('A', 5000)}`);
console.log(`calculateBonus B:${calculateBonus('B', 14000)}`);

策略模式生成运行代码

在前面的文章中 为文章的高亮代码加上点击运行,实际里面就运用了策略模式来为不同类型的代码实现生成对应的dom节点

  • 策略类 根据不同的代码类型来生成不同的代码,符合策略模式中为相同的 业务规则,使之可以替换。
  • 生产代码方法通过不同的类型请求代理方法进行计算,生产统一的dom节点
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 生成代码相应的dom元素
var genCodeStrategy = {
css: function (code) {
var style = window.document.createElement('style');
style.type = 'text/css';
style.innerHTML = code;
return style;
},
js: function (code) {
var js = window.document.createElement('script');
// 各代码块独立作用域
js.text = '(function() {\n' + code + '\n}());';
return js;
},
script: function (src) {
var script = window.document.createElement('script');
script.src = src;
return script;
},
link: function(href) {
var link = window.document.createElement('link');
link.href = href;
link.rel = 'stylesheet';
link.type = 'text/css';
return link;
},
html: function (code) {
var dom = window.document.createElement('div');
dom.classList.add('xxSection');
dom.innerHTML = code;
return dom;
}
};

// 需要生产dom元素的代码
const runCodeObj = [{
"type": "link",
"code": "https://cdn.bootcss.com/normalize/8.0.1/normalize.min.css"
},{
"type": "link",
"code": "http://localhost:4000/lib/vconsole/custom.css"
},{
"type": "html",
"code":"<div class=\"test\">\n <h1 class=\"ymm\">嘿嘿嘿嘿</h1>\n <h2>HTML 功能测试</h2>\n <button id=\"button\">我是 Button1</button>\n</div>\n"
},{
"type":"css",
"code":".ymm {\n color: red;\n}\n.test {\n position: relative;\n padding: 20px;\n background-color: #ccc;\n}\n"
}];

runCodeObj.forEach(function (item) {
const { type, code } = item;
const domItem = genCodeStrategy[type](code);
console.log('domItem: ');
console.log(domItem);
// do something...
});

另外像书中提到的提取动画类型为不同的策略,表单验证中为不同类型验证提取策略。提取有共同业务规则的部分来使用不同的策略实现,也分离了变化和不变的部分,符合开放封闭原则

总结

策略模式是一种常用且有效的设计模式,它利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。它提供了对开放—封闭原则的完美支持,将算法封装在独立的strategy中,使得它们易于切换,易于理解,易于扩展

当然,策略模式也有一些缺点,但这些缺点并不严重。首先,使用策略模式会在程序中增加许多策略类或者策略对象,但实际上这比把它们负责的逻辑堆砌在Context中要好。其次,要使用策略模式,必须了解所有的strategy,必须了解各个strategy之间的不同点,这样才能选择一个合适的strategy。