设计模式——策略模式

本文大约1600字,将会通俗的介绍什么是策略模式,以及策略模式的优缺点与适用的场景

!!!原创文章,转载请注明来源: pany.fun

#什么是策略

要理解策略模式,首先要知道什么是策略。

通俗的来说,策略也可以理解为决策,即根据某些条件做出某些行为。例如 “兵来将挡,水来土掩”,这就是策略。

我们尝试将它转换为伪代码来理解编程语言中的策略

if (兵) {
    将挡
} else if (水) {
    土掩
}

编程语言中,策略往往关联到条件语句。一个条件语句的分支 即是 一个策略,多个条件语句则能够组成一个策略组。

#什么是策略模式

策略模式可以理解为对条件语句的一种解耦优化。相同的需求,使用策略模式相比使用条件语句而言,更易维护、更易扩展、且低耦合。

关于什么是策略模式的维基定义

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法

对策略模式很难三言两语的理解清楚,我们将在后续讲解中去理解。

#抽象

一个事情涉及到抽象,往往抽象部分就会成为这个事情的核心,也会成为相对难以理解的部分。例如从c进化到c++时,抽象就是c++的核心思想。同样的,抽象也是策略模式的核心思想。

我们将通过常规的条件语句写法以及策略模式写法来理解 抽象

- 条件语句写法

假设我们在某个文件1中,有这么一个判断需求

if (x == a) {
    // do something a
} else if (x == b) {
    // do something b
} else if (x == c) {
    // do something c
} else {
    // do something default
}

而在某个文件2中,我们又有这么一个需求

if (x == a) {
    // do something a1
} else if (x == b) {
    // do something b1
} else if (x == c) {
    // do something c1
} else {
    // do something default1
}

更复杂的情况下,我们可能还会有文件3、文件4 等等 都需要进行这种判断然后执行不同的行为,又因为不在同一个文件而无法整合。

这种需求并不是我们YY出来的,而是真实存在的。例如我们上传文件时,就需要根据文件类型判断请求token的url及参数,也需要根据文件类型判断上传到哪里去(例如图片上传到七牛,日志上传到自己服务器),也需要根据文件类型处理上传参数,甚至还需要根据文件类型来判断怎么处理数据的解析

基于策略模式的文件上传组件

这种写法是最常见也是我们最先想到的,但是它的问题也是显而易见的,一旦后期需要添加一个条件(例如x==d),我们需要给每个文件中的条件语句都进行添加,维护成本很高而且容易遗漏

- 策略模式的抽象

策略模式的优化点在于,充分利用面向对象的多态特性,即使相同的方法(相同的判断条件),不同的子类也能够有不同的实现(执行不同的行为)

策略模式的抽象逻辑

  • 将相同的判断条件(例如x==a),抽象为一个类
  • 将一处判断逻辑封装为一个实例方法
  • 将相同判断条件下的不同行为算法(例如 do a,do a1),抽象为不同子类下对父类实例方法的覆盖

我们将通过代码来更深层次的理解这两个抽象

- 策略模式写法

// 抽象
Class Base {
    - doSth {
        // do something default
    }
    - doSth1 {
        // do something default1
    }
}

Class A : Base {
    - doSth {
        // do something a
    }
    - doSth1 {
        // do something a1
    }
}

Class B : Base {
    - doSth {
        // do something b
    }
    - doSth1 {
        // do something b1
    }
}

Class C : Base {
    - doSth {
        // do something c
    }
    - doSth1 {
        // do something c1
    }
}

我们将条件语句中的default条件抽象成了Base类,因为我们条件语句写法中有两处判断逻辑(文件1和文件2,共2次),所以我们的Base类中提供了两个方法,doSth和doSth1,doSth中执行的是文件1中的default条件下的行为算法,doSth1中执行的是文件2中的default条件下的行为算法。对于条件x==a、x==b、x==c 我们同样进行了一系列抽象。

抽象结束后,我们当然需要判断能够执行,那么在抽象模式下我们如何执行判断

(_kindof Class Base) x
// 文件1中
[x doSth];

// 文件2中
[x doSth1];

我们无需明确的知道x是什么类,只需要确定它是我们的条件类Base或其子类即可

当我们调用某个方法时,由于多态的特性,不同的类能够执行自己的实现,也就达到了根据情况执行行为的目的。

- 策略模式的扩展

前面我们提到了扩展条件d,对于条件语句来说,是非常容易出错的,但是对于策略模式来说,它非常简单。

我们只需要添加Class D,并实现相应的doSth、doSth1即可。维护成本非常低。

#策略模式的优缺点

- 优点

  • 易扩展,维护成本低
  • 低耦合,将判断条件及行为从文件中统一到一个类中

- 缺点

  • 会导致类/文件增加…

#策略模式适合的场景

通过上面优缺点其实很容易总结出策略模式的适用场景

当相同条件,我们只需要进行一次判断逻辑的时候,显然条件语句是更合适的,它不会增加类也不会增加文件,且因为只有一处所以没有太多维护成本

当相同条件,我们需要多次判断执行不同行为的时候,策略模式是更合适的,它能够解除耦合并减少后期维护成本

创作不易,转载请注明来源!pany.fun
本文链接:http://pany.fun/post/策略模式/