Java如何避免过多的if else、switch case

前言:
最近在开发的过程中,发现代码不优化的话,会出现很多的if else,改成switch case也避免不了代码竖向扩展,感觉蛮冗余的,我的场景是这样的,一个电商平台在淘宝、京东、拼多多、苏宁、小红书等渠道都有店铺,不同的渠道需要对订单进行不同的处理,如果你有类似这样的场景,不妨可以参考一下本文,如果文章有误或者有更好的解决方案,还望指出。

本文涉及的代码在github上,点击 链接 可查看源码。

文章会给出两种解决方案,第一种是结合简单工厂模式和策略模式,第二种是利用Java8内置的函数式接口,精简了代码,我在开发中也是用这个方案来简化代码。

我们先来看这样的一个场景:根据快递包裹的重量计算快递公司的邮费,不同的快递公司有不同的邮费计算方式,如京东,申通,圆通等快递公司的邮费计算都是不一样的。

  • 快递公司枚举类如下:
public enum ParcelCompanyEnum {

    ZTO("中通快递"),YTO("圆通快递"),STO("申通快递"),JD("京东快递");

    String name;

    ParcelCompanyEnum(String name) {
        this.name = name;
    }
}
  • if else的方式,可以看到代码有些冗余:
    public Double calculatePostage1(ParcelCompanyEnum company, Integer weight) {
        if (company == ParcelCompanyEnum.JD) {
            return 10 + weight * 1.2;
        } else if (company == ParcelCompanyEnum.STO) {
            return 12 + weight * 0.8;
        } else if (company == ParcelCompanyEnum.YTO) {
            return 8 + weight * 1.5;
        } else if (company == ParcelCompanyEnum.ZTO) {
            return 9 + weight * 1.1;
        } else {
            throw new IllegalArgumentException("No such company :" + company);
        }
    }
  • 换成switch case 精简了不少代码,如果快递公司很多的话,看上去还是蛮冗余的:
    public Double calculatePostage2(ParcelCompanyEnum company, Integer weight) {
        switch (company) {
            case JD: return 10 + weight * 1.2;
            case STO: return 12 + weight * 0.8;
            case YTO: return 8 + weight * 1.5;
            case ZTO: return 9 + weight * 1.1;
            default: throw new IllegalArgumentException("No such company :"+company);
        }
    }
一、结合简单工厂模式和策略模式优化代码

简单工厂模式(Simple Factory Pattern):有一个工厂类,通过传递不同的参数,返回不同所需的对象,简而言之是造对象。

策略模式(Strategy Pattern):将不同的策略(所实现的功能)封装起来,客户端在运行时选择某种策略(解决方案)来执行。

我们需要对不同快递公司计算不同的邮费当成是策略,在需要计算邮费的时候根据快递公司来选择不同的策略来计算邮费。

  • 计算邮费策略接口:
public interface CalculateStrategy {
    Double calculate(Integer weight);
}
  • 京东快递邮费计算,实现策略接口:
public class CalculateStrategyJd implements CalculateStrategy {
    @Override
    public Double calculate(Integer weight) {
        return 10 + weight * 1.2;
    }
}
  • 申通快递邮费计算,实现策略接口:
public class CalculateStrategySto implements CalculateStrategy {
    @Override
    public Double calculate(Integer weight) {
        return 12 + weight * 0.8;
    }
}
  • 圆通快递邮费计算,实现策略接口:
public class CalculateStrategyYto implements CalculateStrategy {
    @Override
    public Double calculate(Integer weight) {
        return 8 + weight * 1.5;
    }
}
  • 中通快递邮费计算,实现策略接口:
public class CalculateStrategyZto implements CalculateStrategy {
    @Override
    public Double calculate(Integer weight) {
        return 9 + weight * 1.1;
    }
}

我们还需一个工厂类,负责创建实现策略接口的类,其实这里的Map起了很大的作用,也是这里避免过多的if else、switch case逻辑,运用简单工厂模式和策略模式实际上也做了解耦,因为在实际开发中对不同分支逻辑的处理可不是这么简单的一条公式,工厂类如下:

public class CalculateFactory {
    private Map<ParcelCompanyEnum, CalculateStrategy> map = new HashMap<>(5);

    {
        map.put(ParcelCompanyEnum.JD, new CalculateStrategyJd());
        map.put(ParcelCompanyEnum.YTO, new CalculateStrategyYto());
        map.put(ParcelCompanyEnum.ZTO, new CalculateStrategyZto());
        map.put(ParcelCompanyEnum.STO, new CalculateStrategySto());
    }
    public CalculateStrategy creat(ParcelCompanyEnum company) {
        return map.get(company);
    }
}

有人可能会想,能不能Map的value直接是计算邮费的方法呢?实际上是有的,待会且看方案二,用Java8内置函数式接口来完成。
接着,我们只需要定义一个这样的方法,就可以用简单工厂模式和策略模式来完成计算邮费了:

    public Double calculatePostage3(ParcelCompanyEnum company, Integer weight) {
        CalculateFactory factory = new CalculateFactory();
        return factory.creat(company).calculate(weight);
    }
二、利用Java8内置函数式接口优化代码

计算邮费的类,这里就不给出全部代码了,只给出运用Java8内置接口的相关逻辑,如果要看全代码的话,文章开头处有链接,这里用的是Java8的内置接口Function<T,R>,待实现的方法逻辑是参数类型传入泛型T类,返回类型是泛型R类,可以看我们的例子,Map的value是Function<Integer, Double>,我们需要实现apply方法,方法参数类型是Integer,即重量,方法返回类型是Double,即邮费,代码如下:

public class CalculatePostage {

     Map<ParcelCompanyEnum, Function<Integer, Double>> map = new HashMap<>(5);

    {
        map.put(ParcelCompanyEnum.JD, this::calculateJd);
        map.put(ParcelCompanyEnum.STO, this::calculatSto);
        map.put(ParcelCompanyEnum.YTO, this::calculateYto);
        map.put(ParcelCompanyEnum.ZTO, this::calculateZto);
    }
    public Double calculateJd(Integer weight) {
        return 10 + weight * 1.2;
    }
    public Double calculatSto(Integer weight) {
        return 12 + weight * 0.8;
    }
    public Double calculateYto(Integer weight) {
        return 8 + weight * 1.5;
    }
    public Double calculateZto(Integer weight) {
        return 9 + weight * 1.1;
    }
}

综合方案一和方案二,客户端代码如下:

public class Client {

    public static void main(String[] args) {
        ParcelCompanyEnum company = ParcelCompanyEnum.JD;
        Integer weight = 15;
        CalculatePostage calculatePostage = new CalculatePostage();

        System.out.println("if else 计算邮费:" + calculatePostage.calculatePostage1(company, weight));

        System.out.println("switch case 计算邮费:" + calculatePostage.calculatePostage2(company, weight));

        System.out.println("传统工厂模式 + 策略模式 计算邮费:" + calculatePostage.calculatePostage3(company, weight));

        System.out.println("Java8 lambda + 策略模式 计算邮费:" + calculatePostage.map.get(company).apply(weight));
    }
}

Java8内置的函数式接口:

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
三、拓展Java8提供的内置函数式接口
内置函数式接口
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355