前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何利用策略模式避免if-else判断代码

如何利用策略模式避免if-else判断代码

作者头像
chenchenchen
发布2021-09-06 10:49:59
6990
发布2021-09-06 10:49:59
举报
文章被收录于专栏:chenchenchen

策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

结构图

图片
图片

角色与理解

  • 策略模式共分为三种角色:
    • Context(上下文环境):持有抽象策略类,调用策略方法。
    • Strategy(抽象策略类):声明策略方法。
    • Concrete Strategy(具体策略类):实现策略方法。
  • Context持有State的引用,完成对ConcreteStrategy中策略方法的调用

核心代码

  • 抽象策略类
代码语言:javascript
复制
public interface Strategy {
    void doSomething();
}
  • 真实策略类
代码语言:javascript
复制
public class ConcreteStrategyA implements Strategy {
    @Override
    public void doSomething() {
        System.out.println("AAA");
    }
}
public class ConcreteStrategyB implements Strategy {
    @Override
    public void doSomething() {
        System.out.println("BBB");
    }
}
  • 客户端
代码语言:javascript
复制
public class Client {
    public static void main(String[] args) {
        Strategy strategy = new ConcreteStrategyA();
        strategy.doSomething();
        strategy = new ConcreteStrategyB();
        strategy.doSomething();
    }
}

结合工厂模式动态选择策略

因为策略模式会包含一组策略,在使用它们的时候,一般会通过类型(type)来判断创建哪个策略来使用。为了封装创建逻辑,我们需要对客户端代码屏蔽创建细节。我们可以把根据 type 创建策略的逻辑抽离出来,放到工厂类中。示例代码如下所示

一般来讲,如果策略类是无状态的,不包含成员变量,只是纯粹的算法实现,这样的策略对象是可以被共享使用的,不需要在每次调用 getStrategy() 的时候,都创建一个新的策略对象。针对这种情况,我们可以使用上面这种工厂类的实现方式,事先创建好每个策略对象,缓存到工厂类中,用的时候直接返回。

相反,如果策略类是有状态的,根据业务场景的需要,我们希望每次从工厂方法中,获得的都是新创建的策略对象,而不是缓存好可共享的策略对象,那我们就需要按照如下方式来实现策略工厂类。

策略模式的使用

最常见的是运行时动态确定使用哪种策略,这也是策略模式最典型的应用场景。这里的“运行时动态”指的是,我们事先并不知道会使用哪个策略,而是在程序运行期间,根据配置、用户输入、计算结果等这些不确定因素,动态决定使用哪种策略。

“非运行时动态确定”,并不能发挥策略模式的优势。在这种应用场景下,策略模式实际上退化成了“面向对象的多态特性”或“基于接口而非实现编程原则”。

示例

策略模式适用于根据不同类型的动态,决定使用哪种策略这样一种应用场景。我们先通过一个例子来看下,if-else 或 switch-case 分支判断逻辑是如何产生的。具体的代码如下所示。在这个例子中,我们没有使用策略模式,而是将策略的定义、创建、使用直接耦合在一起。

如何来移除掉分支判断辑呢?那策略模式就派上用场了。我们使用策略模式对上面的代码重构,将不同类型订单的打折策略设计成策略类,并由工厂类来负责创建策略对象。具体的代码如下所示:

重构之后的代码就没有了 if-else 分支判断语句了。实际上,这得益于策略工厂类。在工厂类中,我们用 Map 来缓存策略,根据 type 直接从 Map 中获取对应的策略,从而避免 if-else 分支判断逻辑。等后面讲到使用状态模式来避免分支判断逻辑的时候,你会发现,它们使用的是同样的套路。本质上都是借助“查表法”,根据 type 查表(代码中的 strategies 就是表)替代根据 type 分支判断。但是,如果业务场景需要每次都创建不同的策略对象,我们就要用另外一种工厂类的实现方式了。具体的代码如下所示:

总结

策略模式定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。策略模式用来解耦策略的定义、创建、使用。实际上,一个完整的策略模式就是由这三个部分组成的。策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。策略的创建由工厂类来完成,封装策略创建的细节。策略模式包含一组策略可选,客户端代码如何选择使用哪个策略,有两种确定方法:编译时静态确定和运行时动态确定。其中,“运行时动态确定”才是策略模式最典型的应用场景。除此之外,我们还可以通过策略模式来移除 if-else 分支判断。实际上,这得益于策略工厂类,更本质上点讲,是借助“查表法”,根据 type 查表替代根据 type 分支判断。

参考:

https://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&mid=2247493387&idx=3&sn=2bb1dc331d0d8bea87254d0acd127e44&chksm=fd63f7b4ca147ea2dd2271aef42af3e8c7c744730533f92d7828853d1c8920c3f36b9ac9be89&scene=21#wechat_redirect

https://mp.weixin.qq.com/s/dnA_9Fpzlh6mkl6LcyO9hw

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/01/13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 策略模式
  • 结构图
  • 角色与理解
  • 核心代码
  • 结合工厂模式动态选择策略
  • 策略模式的使用
  • 示例
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档