JavaScript 设计模式——策略模式

JavaScript 设计模式——策略模式

  • 1. 什么是策略模式
  • 2. 策略模式的实现
  • 3. JavaScript 中的策略模式
  • 4. 策略模式的优缺点

1. 什么是策略模式

策略模式 是一种行为设计模式,能让我们定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。

2. 策略模式的实现

试想这样一个场景,在实现编译器中的四则运算时,将符号(加减乘除)和两个参与运算的数字传入函数中,返回对应的结果

最初代码:

const calc = function(type, num1, num2) {
  if(type === '+'){
	return num1 + num2
  }
  if(type === '-') {
	return num1 - num2
  }
  if(type === '*'){
	return num1 * num2;
  }
  if(type === '/'){
	return num1 / num2;
  }
}

calc('+', 1, 2); 		// 3
calc('-', 3, 1);		// 2

calc 函数缺乏弹性。如果未来又有引入了取模运算,那必须深入到 calc 函数的内部实现,这违反了开放-封闭原则。

下面我们使用策略模式重构这段代码。一个基于策略模式的程序至少包含两部分:1. 一组策略类,封装了具体的算法与计算过程;2. 环境类 Context,接收客户的请求,将请求委托给某一个策略类。

// 一组策略类
const calcSum = function() {}
calcSum.prototype.calc = function(num1, num2) {
  return num1 + num2;
}
const calcDifference = function() {}
calcDifference.prototype.calc= function(num1, num2) {
  return num1 - num2;
}
const calcQuadrature = function() {}
calcQuadrature.prototype.calc = function(num1, num2) {
  return num1 * num2;
}
const calcQuotient = function() {}
calcQuotient.prototype.calc = function(num1, num2) {
  return num1 / num2;
}

// 定义运算类
const CalcRes = function(){
  this.num1 = null;
  this.num2 = null;
  this.strategy = null;
}
CalcRes.prtotype.setOperands = function(num1, num2){
  this.num1 = num1;
  this.num2 = num2;
}
CalcRes.prototype.setStrategy = function(strategy) {
	this.strategy = strategy;
}
CalcRes.prototype.getRes = function(){
	return this.strategy.calc(this.num1, this.num2)
}

// 使用
const res = new CalRes();
res.setOperands(1, 2);
res.setStrategy(new calcSum());		// 设置策略对象
console.log(res.getRes());			// 3

res.setStrategy(new calcDifference());	// 设置策略对象
console.log(res.getRes());				// -1

3. JavaScript 中的策略模式

上面的实现是让 strategy 对象从类中创建,这是模拟面向对象语言的实现。JavaScript 中的函数也是对象,于是可以把 strategy 直接定义为函数。

const strategies = {
  add: function(num1, num2){
	return num1 + num2;
  },
  subtract: function(num1, num2){
	return num1 - num2;
  },
  multiply: function(num1, num2){
	return num1 * num2;
  },
  divide: function(num1, num2){
	return num1 / num2;
  },
}

const calcRes = function(type, num1, num2){
  return strategies[type](num1, num2);
}

console.log(calcRes('add', 1, 2));			// 3
console.log(calcRes('multiply', 1, 2));		// 2

在 JavaScript 这种将函数作为一等对象的语言里,策略模式已经融入到了语言本身当中,我们经常用高阶函数来封装不同的行为,并把它传递到另一个函数中。

在之前的例子中,为了清楚地表示这是一个策略模式,我们特意使用了 strategies 这个名字。如果去掉 strategies,我们仍然要认出这是一个策略模式。

const add = function(num1, num2) {
  return num1 + num2;
}
const subtract = function(num1, num2){
  return num1 - num2;
}
const multiply = function(num1, num2){
  return num1 * num2;
}
const divide = function(num1, num2){
  return num1 / num2;
}

const calcRes = function(fn, num1, num2) {
  return fn(num1, num2);
}

calcRes(add, 1, 2);			// 3

4. 策略模式的优缺点

优点:

  1. 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。
  2. 策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展。
  3. 策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
  4. 在策略模式中利用组合和委托来让 Context 拥有执行算法的能力,这也是继承的一种更轻便的替代方案。

策略模式也有缺点,但缺点并不严重。要使用策略模式,必须了解所有的 strategy,必须了解各个 strategy 之间的不同点, 这样才能选择一个合适的 strategy。

你可能感兴趣的:(JavaScript,设计模式,策略模式,设计模式)