设计模式使用心得 -- 策略模式

今天开始研究并记录下自己项目中设计模式的应用。

策略模式

1. WHAT -- 什么是策略模式(Strategy)

定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

比较难懂,下面我会用一个实际的例子来解释一下。

2. WHEN -- 什么情况下使用策略模式

现在我的项目中有个扫码功能需要实现。

扫码功能需求:

  1. 应用中的扫码功能有多个入口,分别为首页右上角、其他一级界面、 二级界面。
  2. 二级界面扫码需要实现:功能A,二维码无效提醒
  3. 其他一节界面扫码需要实现:功能B,二维码无效提醒
  4. 首页右上角扫码需要实现:功能A、功能B、功能C,二维码无效提醒

初版设计方案

  1. 一个公共扫码界面:进入界面时需要携带扫码入口参数,比如首页key、二级界面key等等

  2. 一个处理扫码结果的业务逻辑类

    2.1. 通过if-else对入口参数进行判断

    2.2. 对扫码结果进行对应入口所需要实现的功能逻辑处理 代码实现大概就是下面这个样子:

...
if (from == ScanFrom.home){
    if (handleA(scanResult)) {
        ...
    } else if (handleB(scanResult)) {
        ...
    } else if (handleC(scanResult)) {
        ...
    } else {
        handleInvalidScanResult();
    }
} else if (from == ScanFrom.detail) {
    if (handleA(scanResult)) {
        ...
    }
} else if (from == ScanFrom.my) {
    if (handleB(scanResult)) {
        ...
    }
}
...

大家会看到上面嵌套了2层if-else,如果需要在处理结果中再进行判断,则会嵌套更多层。

这样写有很多不好的地方:

1、多层嵌套后,即使封装成了方法也会使得这个逻辑处理类显得异常庞大

2、后期需要添加新的扫码入口时,就需要在后面继续添加else if,对于这个类来说维护起来很不方便

3、违反了“开闭原则”,后期如果需要在某个或某几个入口添加新功能的时候,又是一笔巨大的工作量

所以,为了解决1(大量if-else嵌套)、2(大量并列if-else条件判断)、3(违反‘开闭原则’)这两个问题,我选择使用策略模式来进行优化。

3. HOW -- 怎么使用策略模式

3.1 创建策略抽象类(ScanScene),把具体的处理场景给抽象出来;

3.2 创建具体策略类(ScanSceneHome、ScanSceneDetail等等),实现每个场景中扫码的具体逻辑;

3.3 创建环境类(ScanStrategyManager),在类中添加具体的ScanScene具体策略类,然后实现根据传入的scene不同,选择不同的ScanScene来进行处理。

3.4 使用时,把对应场景的scene当作key,把具体策略ScanSceneXxx当作value保存在 ScanStrategyManager的scanSceneMaps中,比如:scanSceneMaps.add('home', >ScanSceneHome())

3.5 在其他类中使用时,可以直接调用ScanStrategyManager(环境类)中的handleScanResult方法,通过传入scene(场景参数)scanResult(扫码结果参数)来对扫码结果进行相应场景的处理。

image.png

4. WHY -- 为什么策略模式能够解决上面的3个问题

1、嵌套if-else: 由于把并列的if-else中的内容都抽取成具体策略类,所以在ScanStrategyManager(环境类)中的子if-else都不存在了,只保留了一层场景if-else判断

2、并列if-else: 由于把具体场景类通过场景(key)-具体策略类(value)的方式保存到map中,使用时根据传入的scene参数作为key,直接从map中获取到对应的值,进而取消了大量的并列if-else,后续在新增场景的时候,也不用去在添加if-else,只需要在map中添加对应的键值对即可。

3、开闭原则: 由于使用了map的方式来保存具体策略类,所以在后续的开发中,不需要对该类进行修改,只需要通过map的add方法即可添加具体的策略类