定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对Context发起请求的时候,Context总是把请求委托给策略对象中间的某一个进行计算。
一、策略模式
1.基本策略模式
计算某公司员工绩效,S奖金4,A3,B*2
(1)基本实现
let calculate = function (level, salary) {
if (level === 'S') {
return salary * 4;
}
if (level === 'A') {
return salary * 3;
}
if (level === 'B') {
return salary * 2;
}
}
以上代码实现了一个基本的计算功能,但是该函数会随着业务的复杂程度而变得更加复杂(因为主要是使用if-else语句实现的),且函数的复用性不强。
(2)考虑使用组合函数来重构代码
let funcA = function (salary) {
return salary * 4;
}
let funB = function (salary) {
return salary * 3;
}
let funC = function (salary) {
return salary * 2;
}
let calculate = function (level, salary) {
if (level === 'S') {
return funcA(salary);
}
if (level === 'A') {
return funcA(salary);
}
if (level === 'B') {
return funcB(salary);
}
}
以上代码针对之前的写法有了一定的优化,但是仍然没有改变calculate会变得越来越庞大且缺乏弹性的问题。
(3)使用策略模式
let funcS = function () { };
funcS.prototype.calculate = function (salary) {
return salary * 4;
}
let funcA = function () { };
funcA.prototype.calculate = function (salary) {
return salary * 3;
}
let funcB = function () { };
funcB.prototype.calculate = function (salary) {
return salary * 2;
}
let Bouns = function () {
this.salary = null;
this.salary = null;
}
Bouns.prototype.setSalary = function (salary) {
this.salary = salary;
}
Bouns.prototype.setStrategy = function (strategy) {
this.strategy = strategy;
}
Bouns.prototype.getBonus = function () {
if (!this.strategy) {
throw new Error('未设置strategy属性');
}
return this.strategy.calculate(this.salary);
}
最后使用策略模式重构了代码,重构后的代码更加清晰,各个类的职责更加鲜明。以上是基于面向对象语言的策略模式,关于JavaScript还有它自身的策略模式的实现。
2.JavaScript版本的策略模式
let strategies = {
'S': function (salary) {
return salary * 4;
},
'A': function (salary) {
return salary * 3;
},
'B': function (salary) {
return salary * 2;
}
}
let calculate = function (level, salary) {
return strategies[level](salary);
}
以上代码利用JavaScript的特性实现了策略模式,在JavaScript中函数也是对象,所以可以直接将各个策略定义成函数,同时奖金类在JavaScript中同样可以用函数来代替。
二、代理模式
为一个对象提供一个代用品或占位符,以便控制对它的访问
1.基本代理
let temp = {
send: (target) => {
let value = 1;
target.receive(value);
}
}
let A = {
receive(value) {
B.receive(value);
}
}
let B = {
receive(value) {
console.log(value);
}
}
temp.send(A); //1
以上代码实现了一个基本的代理模式
2.虚拟代理
虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。
let Image = (function () {
let imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc: function (src) {
imgNode.src = src;
}
}
})();
let proxyImg = (function () {
let img = new Image;
img.onload = function () {
Image.setSrc(this.src);
}
return {
setSrc: function (src) {
Image.setSrc('loading.gif');
img.src = src;
}
}
})();
Image.setSrc('http://volit.com/1.png');
以上代码使用虚拟代理模式实现了一个图片预加载功能,在图片加载完成之前,先用一张加载gif动图来代替原图片