-
Notifications
You must be signed in to change notification settings - Fork 50
设计模式之「行为型模式」 #27
Comments
策略模式
策略模式的核心是将每个算法封装起来,与每个算法的调用隔离开。对于策略模式能够抽象的算法来说,不变的是接口(每个算法调用的方式),变的是算法的实现(包括有多少个算法,和每个算法是如何实现的)。 所以,针对使用策略模式抽象的代码,有两个部分需要实现:一个是策略类(Strategy),封装了具体的算法,并负责具体的实现过程。第二个是环境类(Context),环境类负责将策略类封装的代码插入到当前环境中。 策略模式将算法的责任和算法本身分离开,这样既可以提高了策略类的复用性(因为策略类中算法的实现与环境无关),又符合了单一职责原则,又支持了开闭原则(只需在策略类中增加算法的实现即可)。 实现代码实现: var strategies = {
'S': (salary)=> salary * 4,
'A': (salary) => salary * 3,
'B': (salary) => salary * 2
}
var calcBonus = (level, salary) => strategies[level](salary)
console.log(calcBonus('S', 20000))
console.log(calcBonus('A', 10000)) 分析:
|
迭代器模式其实迭代器模式我们已经很熟悉了,ES5 带来的 内部迭代器在函数的内部已经定义好了迭代规则,外部只需要调用一次,传入迭代的参数,之后整个迭代规则将由内部迭代器完成。 外部迭代器则必须显示的请求迭代下一请求,相当于只是完成了读取下一个迭代元素的任务,其他的均由外部负责。 可以看到,内部迭代器来的要方便的多,只需传入一次参数即可。但是也因为内部迭代器封装了迭代的规则。导致拓展性不够,就需要使用外部迭代器。 实现内部迭代器实现一个简易版的 Array.prototype.forEach2 = function(callback, that) {
let T
if (this == null) {
throw new TypeError(' this is null or not defined');
}
let O = Object(this)
let len = O.length;
if (typeof callback !== "function") {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = thisArg; // 如果未提供 T,则为 undefined
}
for (let i = 0; i < len; i++) {
if (i in O) {
callback.call(T, O[i], i, O)
}
}
}
;
['a', 'b', 'c'].forEach2((item, index) => {
console.log(`item - ${item}, index - ${index}`)
}) 外部迭代器其实外部迭代器实现起来更简单,ES6 也添加了 Iterator 接口,我们可以通过 function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
} |
责任链模式在我们写写业务逻辑的时候,经常会遇到多个 if,elseif,else 嵌套的分支语句,并且每个逻辑判断都会是一大长串,并且当后来再去修改时会发现试图理清多个嵌套的判断逻辑是多么的困难。 设计模式的作用就是分离变化与不变化的部分。其中变化的部分就是判断的逻辑,有点像策略模式中的每个策略算法,每个分支语句就是变化的部分,他们可以随业务逻辑添加删除或修改,所以必须将他们抽象出来,这样才符合开闭原则。 像策略模式使用字符串的 key 代替 实现逻辑耦合的责任链const order1 = function(orderType, pay, stock) {
if ( /* logic */ ) {
/* do something */
} else {
order2(orderType, pay, stock)
}
}
const order2 = function(orderType, pay, stock) {
if ( /* logic */ ) {
/* do something */
} else {
orderNormal(orderType, pay, stock)
}
} 这种责任链模式其实还是没有将业务函数与责任链的传递分离,责任链的节点顺序被硬编码进了业务函数中,但是好处是实现的简单粗暴,至少在一定程度上将 封装一个责任链类为了将责任链的传递与业务函数分离开,每个业务函数返回一个特定的值(字符串)来标志需要调用下一个责任链节点,如果在某节点返回的不是该标志,那么后面的节点将以此被跳过。 const order1 = function(orderType, pay, stock) {
if ( /* logic */ ) {
/* do something */
} else {
return 'NEXT_SUCCEWSSOR'
}
} 接下来,创建一个责任链类来将整个链串起来 const order1 = function(orderType, pay, stock) {
if (orderType === 1 && pay === true) {
console.log('111')
} else {
return 'NEXT_SUCCESSOR'
}
}
const order2 = function(orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('222')
} else {
orderNormal(orderType, pay, stock)
}
}
const orderNormal = function(orderType, pay, stock) {
if (stock > 0) {
console.log('ok')
} else {
console.log('nope')
}
}
class Chain {
constructor(fn) {
this.fn = fn
this.successor = null
}
setNextSuccessor(successor) {
return this.successor = successor
}
passRequest() {
let ret = this.fn.apply(this, arguments)
if (ret === 'NEXT_SUCCESSOR') {
return this.successor && this.successor.passRequest.apply(this.successor, arguments)
}
return ret
}
}
let c1 = new Chain(order1)
let c2 = new Chain(order2)
let cn = new Chain(orderNormal)
c1.setNextSuccessor(c2)
c2.setNextSuccessor(cn)
c1.passRequest(2, true, 500) 更简洁的责任链类上面的责任链类略显繁琐了,需要将每个责任链函数包装,然后再添加到上一个节点后面,下面的封装更简洁,一次成型。但是上面个的责任链类也有好处,就是可以随意打散和添加节点,而保持其他的节点关系不受影响。 class Chain {
constructor(...fns) {
this.fns = fns
this.successor = null
}
passRequest() {
let ret
const fns = this.fns
for (let i = 0; i < fns.length; i++) {
if (typeof fns[i] === 'function') {
ret = fns[i].apply(fns[i], arguments)
}
if (ret !== 'NEXT_SUCCESSOR') {
break;
}
}
return ret
}
}
let c = new Chain(order1, order2, orderNormal)
c.passRequest(2, true, 500) 修改 Function 原型链的 AOPFunction.prototype.after = function(fn) {
let self = this
return function() {
ret ret = self.apply(this, arguments) // this 为调用时的 this
if (ret === 'nextSuccessor') {
return fn.apply(this, arguments) // this 为调用时的 this
}
return ret
}
} 调用时先用 const order = order1.after(order2).after(orderNormal)
order(1, 200) 但是这种方法最大问题是直接修改了 Function 的原型链,除非万不得已,尽量不要修改任何的内置对象。 使用第三方库来实现 AOPmeld 库是用 js 来实现的 AOP 库,demo 如下,可以看到整个 API 基本无侵入,但是一般使用责任链模式都是用来简化逻辑,如果不是大量需要的话,为此专门引入一个第三方库,还是显得有点重了。 var myObject = {
doSomething: function(a, b) {
return a + b;
}
};
// Call a function after myObject.doSomething returns
var remover = meld.after(myObject, 'doSomething', function(result) {
console.log('myObject.doSomething returned: ' + result);
});
myObject.doSomething(1, 2); // Logs: "myObject.doSomething returned: 3"
remover.remove();
myObject.doSomething(1, 2); // Nothing logged |
The text was updated successfully, but these errors were encountered: