JS设计模式-策略模式

1,542 阅读4分钟

本文有我们组内丁武龙分享总结

什么是策略模式

定义

定义一系列的方法,把他们一个个封装成函数,也可把他们作为属性同意封装进一个对象,然后再定义一个方法,该方法可根据参数自动选择执行对应的算法

策略模式主要有两部分构成,一部分是封装不同策略的策略组,另一部分是 Context。通过组合和委托来让 Context 拥有执行策略的能力,从而实现可复用、可扩展和可维护,并且避免大量复制粘贴的工作。

应用场景

一般可用于在实现某一个功能的时候,有很多个方案可选择的情况

在JavaScript中使用策略模式

在理解策略模式之前,我们也来一个例子,根据员工的薪水、绩效等级S,A,B,C来计算年终奖

使用一般方法

var calculation = function( level, salary ){
if ( level === 'S' ){
    return salary * 4;
}
if ( level === 'A' ){
    return salary * 3;
}
if ( level === 'B' ){
    return salary * 2;
}
}
calculation( 'S', 10000 );

上面这段代码暴露了几个问题

  • calculation函数包含了很多if-else语句
  • calculation函数缺乏弹性,假如还有D等级的话,那么我们需要在calculation 函数内添加判断等级D的if语句
  • 算法复用性差,如果在其他的地方也有类似这样的算法的话,但是规则不一样,我们这些代码不能通用

使用组合函数

组合函数是把各种算法封装到一个个的小函数里面,比如等级A的话,封装一个小函数,等级为B的话,也封装一个小函数,以此类推;如下代码:

var A = function(salary) {
    return salary * 4;
};
var B = function(salary) {
    return salary * 3;
};

var C = function(salary) {
    return salary * 2
};
var calculation = function(level,salary) {
    if(level === 'A') {
        return A(salary);
    }
    if(level === 'B') {
        return B(salary);
    }
    if(level === 'C') {
        return C(salary);
    }
};
// 调用如下
console.log(calculation('A',4500)); // 18000

代码看起来有点完善,但是还是有以下问题

  • calculation函数有可能会越来越大,比如增加D等级的时候,而且缺乏弹性。

使用策略模式实现

一个基于策略模式的程序至少有两部分组成,第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类Context,该Context接收客户端的请求,随后把请求委托给某一个策略类。我们先使用传统面向对象来实现

var A = function(){};
A.prototype.calculate = function(salary) {
    return salary * 4;
};

var B = function(){};
B.prototype.calculate = function(salary) {
    return salary * 3;
};

var C = function(){};
C.prototype.calculate = function(salary) {
    return salary * 2;
};
// 奖金类
var Bouns = function(){
    this.salary = null;    // 原始工资
    this.levelObj = null;  // 绩效等级对应的策略对象
};
Bouns.prototype.setSalary = function(salary) {
    this.salary = salary;  // 保存员工的原始工资
};
Bouns.prototype.setlevelObj = function(levelObj){
    this.levelObj = levelObj;  // 设置员工绩效等级对应的策略对象
};
// 取得奖金数
Bouns.prototype.getBouns = function(){
    // 把计算奖金的操作委托给对应的策略对象
    return this.levelObj.calculate(this.salary);
};
var bouns = new Bouns();
bouns.setSalary(10000);
bouns.setlevelObj(new A()); // 设置策略对象
console.log(bouns.getBouns());  // 40000

bouns.setlevelObj(new B()); // 设置策略对象
console.log(bouns.getBouns());  // 30000

如上代码使用策略模式,可以看到代码职责更新分明,代码变得更加清晰。

Javascript版本的策略模式

//策略类Strategy
var setSalary = {
    'S':function(salary) {
        return salary * 4
    }
    'A':function(salary) {
        return salary * 3
    }
    'B':function(salary) {
        return salary * 2
    }
    'C':function(salary) {
        return salary * 1
    }
}
//环境类Context
var calculation = function(level , salary){
    return setSalary[level](salary)
}

//使用
calculation('S' , 10000)

这样就实现了javascript的策略模式了,可以看出代码更加的简单明了了

策略模式有哪些优缺点

优点:

  • 策略模式利用组合,代理等技术和思想,有效的避免很多if条件语句。
  • 策略模式提供了开放-封闭原则,使代码更容易理解和扩展。
  • 策略模式中的代码可以复用

缺点:

  • 增加了许多策略类或者策略对象
  • 要使用策略模式,必须了解所有的strategy,违反了最少知识原则

总结

策略模式定义了一系列算法,从概念上来讲这些算法都是做相同的事,只是实现方法不同,它可以用相同的方式调用所有的方法,减少了各类算法类与使用算法之间的耦合
从另一层面上来说,单独定义算法类也方便了单元测试,因为可以通过自己的算法进行单独测试
在实际运用中,不仅可以封装算法,也可以用来封装几乎任何类型的规则,是要在分析过程中需要在不同时间应用不同的业务规则,就可以考虑是要策略模式来处理各种变化。