page contents

探讨 | 复杂的 if-else 语句“优雅处理”的思路

简单 if-else,可以使用 卫语句 进行优化。 但是在实际开发中,往往不是简单 if-else 结构,我们通常会不经意间写下如下代码: 毫不夸张的说,我们都写过类似的代码,回想起被 if-else 支...

简单 if-else,可以使用 卫语句 进行优化。

但是在实际开发中,往往不是简单 if-else 结构,我们通常会不经意间写下如下代码:


attachments-2019-12-2kFmAV9r5e01cee01fdf3.jpg


毫不夸张的说,我们都写过类似的代码,回想起被 if-else 支配的恐惧,我们常常无所下手,甚至不了了之。

下面分享一下我在开发中遇到复杂的 if-else 语句“优雅处理”思路。

如有不妥,欢迎大家一起交流学习。


需求

假设有这么一个需求:

一个电商系统,当用户消费满1000 金额,可以根据用户VIP等级,享受打折优惠。

根据用户VIP等级,计算出用户最终的费用。

  • 普通会员 不打折

  • 白银会员 优惠50元

  • 黄金会员 8折

  • 白金会员 优惠50元,再打7折

编码实现:

attachments-2019-12-AmhNoewj5e01cee93251c.jpg


为了方便演示,代码上我进行了简单实现,但实际上 if - else 会进行复杂的逻辑计费。

从功能上来说,基本完成,但是对于我这种有代码洁癖的人来说,代码质量上不忍直视。

我们开始着手优化一下我们的第一版代码吧。


思考

看到如上代码,聪明的朋友首先想到的是,这不是典型的策略模式吗?

你可真是个机灵鬼,我们先尝试用策略模式来优化一下代码吧。


策略模式

什么是策略模式?

可能有的朋友还不清楚什么是策略模式,策略模式是定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

比如上述需求,有返利、有打折、有折上折等等。

这些算法本身就是一种策略。并且这些算法可以相互替换的,比如今天我想让 白银会员优惠50,明天可以替换为 白银会员打9折。

说了那么多,不如编码来得实在。

编码如下:


attachments-2019-12-x3JdUF3w5e01cef7b190b.jpgattachments-2019-12-Ru5gP3fc5e01cf06c7ae5.jpg

我们定义来一个 Strategy 接口,并且定义 四个子类,实现接口。在对应的 compute方法 实现自身策略的计费逻辑。


attachments-2019-12-i4FjPjne5e01cf155da58.jpg


然后对应 getResult 方法,根据 type 替换为对应的 用户VIP 策略。这里代码上出现了重复的调用 compute ,我们可以尝试进一步优化。


attachments-2019-12-oCa1G9Fj5e01cf246e293.jpg


我们在这里把 money < 1000 的情况提前 return。更关注于满1000逻辑 ,也可以减少不必要的缩进。


深思

我曾一度以为策略模式不过如此,以为代码优化到这已经可以了。

但是还有一个恐怖的事情,if-else 依然存在 。

我尝试翻阅了许多书籍,查看如何消除策略模式中的 if-else

书中大部分的方法是,使用简单工厂 + 策略模式,把 if - else 切换为 switch 创建一个工厂方法而已。

但是这远远没有达到我想要的效果,打倒 if - else。

直到某一天夜里,大佬在群里分享一个 Java8 小技巧时,从此打开新世界。


工厂 + 策略


attachments-2019-12-LFOrp0dn5e01cf3827eb5.jpg


我们先在 Strategy 新增一个 getType 方法,用来表示 该策略的 type 值。

代码相对简单,这里就不过多介绍了。


attachments-2019-12-fqmNCW3N5e01cf447ab56.jpg


静态内部类单例,单例模式实现的一种,不是本文重点,如不了解,可以自行 google。

我们再着手创建一个 StrategyFactory 工厂类。

StrategyFactory 这里我使用的是静态内部类单例,在构造方法的时候,初始化好 需要的 Strategy,并把 list 转化为 map。

这里 转化就是“灵魂”所在。


toMap

我们先来看看 Java8 语法中的小技巧。

通常情况下,我们遍历 List,手动put到 Map 中。


attachments-2019-12-dCGfVkUn5e01cf517c4f8.jpg


toMap 第一个参数是一个Function,对应 Map 中的 key,第二个参数也是一个Function,strategy -> strategy, 左边strategy 是遍历 strategies 中的每一个strategy,右边strategy则是 Map 对应 value 值。

若是不了解 Java8 语法的朋友,强烈建议看 《Java8 实战》,书中详细的介绍了 Lambda表达式、Stream等语法。


效果


attachments-2019-12-BBAUjag95e01cf5ce33fb.jpg


至此,通过一个工厂类,在我们在 getResult()调用的时候,根据传入 type,即可获取到 对应 Strategy

再也没有可怕的 if-else 语句。


  • 发表于 2019-12-24 16:42
  • 阅读 ( 715 )

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1135 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1470 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章