回想起被if-else 支配的恐惧,下定决心我要打倒 if - else

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

上一篇:这300G的Java资料是我师傅当年给我的,免费分享给大家(已修复)

下一篇:昨天分享资料不小心把百度网盘深处的秘密泄露了已修复

作者:hyzhan43
https://juejin.im/post/5def654f51882512302daeef

简单 if-else,可以使用 卫语句 进行优化。但是在实际开发中,往往不是简单 if-else 结构,我们通常会不经意间写下如下代码:

-------------------- 理想中的 if-else --------------------
public void today() {
 if (isWeekend()) {
 System.out.println("玩游戏")
 } else {;
 System.out.println("上班!");
 }
 }
-------------------- 现实中的 if-else --------------------
if (money >= 1000) {
 if (type == UserType.SILVER_VIP.getCode()) {
 System.out.println("白银会员 优惠50元");
 result = money - 50;
 } else if (type == UserType.GOLD_VIP.getCode()) {
 System.out.println("黄金会员 8折");
 result = money * 0.8;
 } else if (type == UserType.PLATINUM_VIP.getCode()) {
 System.out.println("白金会员 优惠50元,再打7折");
 result = (money - 50) * 0.7;
 } else {
 System.out.println("普通会员 不打折");
 result = money;
 }
 }
//省略 n 个 if-else ......

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

下面分享一下我在开发中遇到复杂的 if-else 语句“优雅处理”思路。如有不妥,欢迎大家一起交流学习。

01 需求

假设有这么一个需求:

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

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

  • 普通会员 不打折

  • 白银会员 优惠50元

  • 黄金会员 8折

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

02 编码实现

private static double getResult(long money, int type) {
 double result = money;
 if (money >= 1000) {
 if (type == UserType.SILVER_VIP.getCode()) {
 System.out.println("白银会员 优惠50元");
 result = money - 50;
 } else if (type == UserType.GOLD_VIP.getCode()) {
 System.out.println("黄金会员 8折");
 result = money * 0.8;
 } else if (type == UserType.PLATINUM_VIP.getCode()) {
 System.out.println("白金会员 优惠50元,再打7折");
 result = (money - 50) * 0.7;
 } else {
 System.out.println("普通会员 不打折");
 result = money;
 }
 }
 return result;
 }

为了方便演示,代码上我进行了简单实现,但实际上 if - else 会进行复杂的逻辑计费。从功能上来说,基本完成,但是对于我这种有代码洁癖的人来说,代码质量上不忍直视。我们开始着手 优化一下我们的第一版代码吧。

03 思考

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

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

04 策略模式

(1)什么是策略模式?

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

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

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

(2)编码

public interface Strategy {
 // 计费方法
 double compute(long money);
}
// 普通会员策略
public class OrdinaryStrategy implements Strategy {
 @Override
 public double compute(long money) {
 System.out.println("普通会员 不打折");
 return money;
 }
 }
// 白银会员策略
public class SilverStrategy implements Strategy {
 @Override
 public double compute(long money) {
 System.out.println("白银会员 优惠50元");
 return money - 50;
 }
 }
// 黄金会员策略
public class GoldStrategy implements Strategy{
 @Override

 public double compute(long money) {

 System.out.println("黄金会员 8折");

 return money * 0.8;

 }

}

// 白金会员策略

public class PlatinumStrategy implements Strategy {

 @Override

 public double compute(long money) {

 System.out.println("白金会员 优惠50元,再打7折");

 return (money - 50) * 0.7;

 }

}

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

private static double getResult(long money, int type) {
 double result = money;

 if (money >= 1000) {

 if (type == UserType.SILVER_VIP.getCode()) {

 result = new SilverStrategy().compute(money);

 } else if (type == UserType.GOLD_VIP.getCode()) {

 result = new GoldStrategy().compute(money);

 } else if (type == UserType.PLATINUM_VIP.getCode()) {

 result = new PlatinumStrategy().compute(money);

 } else {

 result = new OrdinaryStrategy().compute(money);

 }
 }

 return result;

}

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

private static double getResult(long money, int type) {
 if (money < 1000) {

 return money;

 }

 Strategy strategy;

 if (type == UserType.SILVER_VIP.getCode()) {

 strategy = new SilverStrategy();

 } else if (type == UserType.GOLD_VIP.getCode()) {

 strategy = new GoldStrategy();

 } else if (type == UserType.PLATINUM_VIP.getCode()) {

 strategy = new PlatinumStrategy();

 } else {

 strategy = new OrdinaryStrategy();

 }

 return strategy.compute(money);

}

还记得我在第一篇中说到的卫语句吗?我们在这里把 money < 1000 的情况提前 return。更关注于满1000逻辑 ,也可以减少不必要的缩进。

05 深思

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

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

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

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

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

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

06 工厂 + 策略

public interface Strategy {
 double compute(long money);

 // 返回 type

 int getType();

}

public class OrdinaryStrategy implements Strategy {

 @Override

 public double compute(long money) {

 System.out.println("普通会员 不打折");

 return money;

 }

 // 添加 type 返回

 @Override

 public int getType() {

 return UserType.SILVER_VIP.getCode();

 }

}

public class SilverStrategy implements Strategy {

 @Override

 public double compute(long money) {

 System.out.println("白银会员 优惠50元");

 return money - 50;

 }

 // type 返回

 @Override

 public int getType() {

 return UserType.SILVER_VIP.getCode();

 }

}

....省略剩下 Strategy

我们先在 Strategy 新增一个 getType 方法,用来标示 该策略的 type 值。代码相对简单,这里就不过多介绍了

public class StrategyFactory {
 private Map<Integer, Strategy> map;

 public StrategyFactory() {

 List<Strategy> strategies = new ArrayList<>();

 strategies.add(new OrdinaryStrategy());

 strategies.add(new SilverStrategy());

 strategies.add(new GoldStrategy());

 strategies.add(new PlatinumStrategy());

 strategies.add(new PlatinumStrategy());

 // 看这里 看这里 看这里!

 map = strategies.stream().collect(Collectors.toMap(Strategy::getType, strategy -> strategy));

 

 /* 等同上面

 map = new HashMap<>();

 for (Strategy strategy : strategies) {

 map.put(strategy.getType(), strategy);

 }*/

 }

 public static class Holder {

 public static StrategyFactory instance = new StrategyFactory();

 }

 public static StrategyFactory getInstance() {

 return Holder.instance;

 }

 public Strategy get(Integer type) {

 return map.get(type);

 }

}

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

我们再着手创建一个 StrategyFactory 工厂类。StrategyFactory 这里我使用的是静态内部类单例,在构造方法的时候,初始化好 需要的 Strategy,并把 list 转化为 map。这里 转化就是“灵魂”所在。

(1)toMap

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

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

-------------- before -----------------
 map = new HashMap<>();

for (Strategy strategy : strategies) {

 map.put(strategy.getType(), strategy);

}

-------------- after Java8 -----------------

map = strategies.stream().collect(Collectors.toMap(Strategy::getType, strategy -> strategy));

(2)效果

private static double getResult(long money, int type) {
 if (money < 1000) {

 return money;

 }

 Strategy strategy = StrategyFactory.getInstance().get(type);

 

 if (strategy == null){

 throw new IllegalArgumentException("please input right type");

 }

 return strategy.compute(money);

}

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

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

07 后续

后续代码优化上,若是 Java 项目,可以尝试使用自定义注解,注解 Strategy 实现类。

这样可以简化原来需在工厂类 List 添加一个 Stratey 策略。

最后

以上就是我在开发中遇到复杂的 if-else 语句“优雅处理”思路,如有不妥,欢迎大家一起交流学习。

精彩推荐
1、三万字、91道MySQL面试题(2020最新版,建议收藏)2、惊呆了,老外竟然用50中编程语言写“Hello,Word!”,我服了...3、解答千古难题:路由器到底用不用定期关闭?4、技能帖:让JAVA程序员效率翻倍的IDEA技巧总结5、IDEA太强悍了,调试器竟然支持实时数据流分析啦,提前知道代码怎么跑的?6、Java通过Netty,实现Websocket消息推送简单几步搞定7、为什么微服务一定要有网关?8、吐血整理!14 个 Spring MVC 顶级技巧!

点个在看少个 bug
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值