900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > [解锁新姿势] 回想起被 `if-else` 支配的恐惧 我们要打倒 if - else

[解锁新姿势] 回想起被 `if-else` 支配的恐惧 我们要打倒 if - else

时间:2024-07-20 10:28:37

相关推荐

[解锁新姿势] 回想起被 `if-else` 支配的恐惧 我们要打倒 if - else

前言

[解锁新姿势] 兄dei,你代码需要优化了

在之前文章说到,简单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语句“优雅处理”思路。如有不妥,欢迎大家一起交流学习。

需求

假设有这么一个需求:

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

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

普通会员 不打折白银会员 优惠50元黄金会员 8折白金会员 优惠50元,再打7折

编码实现

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会进行复杂的逻辑计费。

从功能上来说,基本完成,但是对于我这种有代码洁癖的人来说,代码质量上不忍直视。我们开始着手优化一下我们的第一版代码吧。

思考

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

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

策略模式

什么是策略模式?

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

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

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

编码

public interface Strategy {// 计费方法double compute(long money);}// 普通会员策略public class OrdinaryStrategy implements Strategy {@Overridepublic double compute(long money) {System.out.println("普通会员 不打折");return money;}}// 白银会员策略public class SilverStrategy implements Strategy {@Overridepublic double compute(long money) {System.out.println("白银会员 优惠50元");return money - 50;}}// 黄金会员策略public class GoldStrategy implements Strategy{@Overridepublic double compute(long money) {System.out.println("黄金会员 8折");return money * 0.8;}}// 白金会员策略public class PlatinumStrategy implements Strategy {@Overridepublic 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 pute(money);}

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

深思

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

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

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

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

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

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

工厂 + 策略

public interface Strategy {double compute(long money);// 返回 typeint getType();}public class OrdinaryStrategy implements Strategy {@Overridepublic double compute(long money) {System.out.println("普通会员 不打折");return money;}// 添加 type 返回@Overridepublic int getType() {return UserType.SILVER_VIP.getCode();}}public class SilverStrategy implements Strategy {@Overridepublic double compute(long money) {System.out.println("白银会员 优惠50元");return money - 50;}// type 返回@Overridepublic 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);}}

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

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

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));

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

效果

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 pute(money);}

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

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

完结撒花撒花 :)

后续

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

这样就可以简化每次都需要在 工厂类 List 添加一个Stratey 策略

最后

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。