java策略枚举:消除在项目里大批量使用if-else的优雅姿势

想起刚开始接触JAVA面向对象编程时,若遇到大量流程判断语句,几乎满屏都是if-else语句,多得让自己都忘了哪里是头,哪里是尾,但是,纵然满屏是if-else,但彼时也没有觉得多别扭。等到编程能力渐渐提升之后,再回过头去看曾经写过的满屏if-else时,脑海里只有一个画面,全都是翔.....

可能初学者都会忽略掉一点,其实if-else是一种面向过程的实现。

那么,如何避免在面向对象编程里大量使用if-else呢?

网络上有很多解决思路,有工厂模式、策略模式、甚至是规则引擎(这个太重了吧)......

这些,都有一个共同的缺点,使用起来还是过于繁重了。虽说避免出现过多的if-else,但是,却会增加很多额外的类,我总觉得,很不实用,只能当做某种模式的学习即可。

可以替换大量的if-else语句,且具备较好的可读性与扩展性,同时能显得轻量化,我比较推荐使用策略枚举来消除if-else。

如何使用呢,下面先从一个业务案例开始说起下——

假如有这样一个需求,需实现一周七天内分别知道要做事情的备忘功能,这里面就会涉及到一个流程判断,你可能会立马想到用if-else,那么,可能是会这样实现——

//if-else形式判断
public String getToDo(String day){
    if("Monday".equals(day)){          ......省略复杂语句
        return "今天上英语课";
    }else if("Tuesday".equals(day)){          .....省略复杂语句          return "今天上语文课";
    }else if("Wednesday".equals(day)){         ......省略复杂语句
        return "今天上数学课";
    }else if("Thursday".equals(day)){         ......省略复杂语句
       return "今天上音乐课";
   }else if("sunday".equals(day)){         ......省略复杂语句
       return "今天上编程课";
   }else{
       此处省略10086行......
   }
}

这种代码,在业务逻辑里,少量还好,若是几百个判断呢,可能整块业务逻辑里都是满屏if-else,既不优雅也显得很少冗余。

这时,就可以考虑使用策略枚举形式来替换这堆面向过程的if-else实现了。

首先,先定义一个getToDo()调用方法,假如传进的是“星期一”,即参数"Monday"。

//策略枚举判断
public String getToDo(String day){
    CheckDay checkDay=new CheckDay();
    return checkDay.day(DayEnum.valueOf(day));
}

在getToDo()方法里,通过DayEnum.valueOf("Monday")可获取到一个DayEnum枚举元素,这里得到的是Monday。

接下来,执行checkDay.day(DayEnum.valueOf("Monday")),会进入到day()方法中,这里,通过dayEnum.toDo()做了一个策略匹配时。注意一点,DayEnum.valueOf("Monday")得到的是枚举中的Monday,这样,实质上就是执行了Monday.toDo(),也就是说,会执行Monday里的toDo()——

public class CheckDay {
    public String day( DayEnum dayEnum) {
        return dayEnum.toDo();
    }
}

上面的执行过程为什么会是这样子呢?只有进入到DayEnum枚举当中,才知道是怎么回事了——(话外音:我第一次接触策略模式时,猛地一惊,原来枚举还可以这样玩)

public enum DayEnum {
    Monday {
        @Override
        public String toDo() {            ......省略复杂语句
            return "今天上英语课";
        }
    },
    Tuesday {
        @Override
        public String toDo() {            ......省略复杂语句
            return "今天上语文课";
        }
    },
    Wednesday {
        @Override
        public String toDo() {            ......省略复杂语句
            return "今天上数学课";
        }
    },
    Thursday {
        @Override
        public String toDo() {            ......省略复杂语句
            return "今天上音乐课";
        }
    };
    public abstract String toDo();
}

在DayEnum枚举属性当中,定义了一个实现了toDo()抽象方法——

public abstract String toDo();

在每个枚举元素当中,都重写了该toDo()抽象方法。这样,当传参DayEnum.valueOf("Monday")流转到dayEnum.toDo()时,实质上是去DayEnum枚举里找到对应Monday定义的枚举元素,然后执行其内部重写的toDo()方法。用if-esle形式表示,就类似"Monday".equals(day)匹配为true时,可得到其内部东西。

总结一下,策略枚举就是枚举当中使用了策略模式,所谓的策略模式,即给你一把钥匙,按照某种约定的方式,可以立马被指引找到可以打开的门。例如,我给你的钥匙叫“Monday”,那么,就可以通过约定方式dayEnum.toDo(),立马找到枚举里的Monday大门,然后进到门里,去做想做的事toDo(),其中,每扇门后的房间都有不同的功能,但它们都有一个相同抽象功能——toDo(),即各房间共同地方都是可以用来做一些事情的功能,但具体可以什么事情,就各有不同了。在本文的案例里,每扇大门里的toDo(),根据不同策略模式可得到不同字符串返回,例如,"今天上英语课"、"今天上语文课",等等。

可见,把流程判断抽取到策略枚举当中,还可以把一堆判断解耦出来,避免在业务代码逻辑里呈现一大片密密麻麻冗余的if-else。

这里,会出现一种情况,即,假如有多个重复共同样功能的判断话,例如,在if-else里,是这样——

public String getToDoByIfElse(String day){
    if("Monday".equals(day)||"Tuesday".equals(day)||"Wednesday".equals(day)){
        ......省略复杂语句
        return "今天上英语课";
    }else if("Thursday".equals(day)){
        ......
    }
}

那么,在策略枚举下应该如何使用从而避免代码冗余呢?

可以参考一下以下思路,设置一个内部策略枚举,将有相同功能的外部引用指向同一个内部枚举元素,这样即可实现调用重复功能了——

public enum DayEnum {
    //指向内部枚举的同一个属性即可执行相同重复功能
    Monday("星期一", Type.ENGLISH),
    Tuesday("星期二", Type.ENGLISH),
    Wednesday("星期三", Type.ENGLISH),
    Thursday("星期四", Type.CHINESE);
    private final Type type;
    private final String day;
    DayEnum(String day, Type type) {
        this.day = day;
        this.type = type;
    }
    String toDo() {
        return type.toDo();
    }
    /**
     * 内部策略枚举
     */
    private enum Type {
        ENGLISH {
            @Override
            public String toDo() {
                ......省略复杂语句
                return "今天上英语课";
            }
        },
        CHINESE {
            @Override
            public String toDo() {
                ......省略复杂语句
                return "今天上语文课";
            }
        };
        public abstract String toDo();
    }
}

若要扩展其判断流程,只需要直接在枚举增加一个属性和内部toDo(实现),就可以增加新的判断流程了,而外部,仍旧用同一个入口dayEnum.toDo()即可。

可能,会有这样一个疑问:为什么在枚举里定义一个抽象方法,会在各个枚举元素里实现呢?

这功能就类似子类继承父类的做法了。DayEnum类似一个父类,DayEnum枚举里的元素就相当是其子类。当父类里定义了抽象方法toDo(),其继承的子类就会默认实现toDo()方法,这样,就会出现枚举里可以这样的写法:

 private enum Type {
        ENGLISH {
            @Override
            public String toDo() {
                return "今天上英语课";
            }
        };
        public abstract String toDo();
    }

我很喜欢在大批量if-else里使用策略枚举来消除替换,总而言之,使用策略枚举可以很灵活处理各种复杂判断,且可读性与扩展性都比较好,它更像是函数式编程,即传进一个参数,就可以得到对应模式下返回的数值。

若Java里业务逻辑中大批量使用if-else,则是面向过程了,因为业务逻辑里的if-else是从上往下一个if接一个if判断下去的,在各个if上打个断点,debug下去,就明白它其实是面向过程的。

由此可知,若项目里有大量的if-else话,着实是一件很影响性能的事情,虽然这点性能可忽略不计,但有更好的取代方案,不是更好吗?

总结

本篇文章就到这里了,希望能给您带来帮助,也希望你能够多多关注我们的更多内容!

(0)

相关推荐

  • 如何避免在Java项目里大批量使用if-else?

    避免大批量使用if-else 可能初学者都会忽略掉一点,其实if-else是一种面向过程的实现. 那么,如何避免在面向对象编程里大量使用if-else呢? 网络上有很多解决思路,有工厂模式.策略模式.甚至是规则引擎(这个太重了吧)...... 这些,都有一个共同的缺点,使用起来还是过于繁重了.虽说避免出现过多的if-else,但是,却会增加很多额外的类,我总觉得,很不实用,只能当做某种模式的学习即可. 可以替换大量的if-else语句,且具备较好的可读性与扩展性,同时能显得轻量化,我比较推荐使用

  • 分析java并发中的wait notify notifyAll

    一.前言 java 面试是否有被问到过,sleep 和 wait 方法的区别,关于这个问题其实不用多说,大多数人都能回答出最主要的两点区别: sleep 是线程的方法, wait / notify / notifyAll 是 Object 类的方法: sleep 不会释放当前线程持有的锁,到时间后程序会继续执行,wait 会释放线程持有的锁并挂起,直到通过 notify 或者 notifyAll 重新获得锁. 另外还有一些参数.异常等区别,不细说了.本文重点记录一下 wait / notify

  • Java编程技巧:if-else优化实践总结归纳

    目录 一.使用策略枚举来优化if-else 二.使用三目运算符来优化if-else 1.根据if-else条件来判断赋值的,如: 2.利用if-else条件来判断调用方法,如: 三.使用Stream优化if中判断条件过多情况 四.使用Map优化if-else 五.使用枚举优化if-else 六.使用Optional类优化if-else 总结 一.使用策略枚举来优化if-else 看到网上蛮多人推荐使用策略模式来优化if-else,但我总觉得,搞一堆策略类来优化大批量if-else,虽然想法很好,

  • Java流程控制语句之If选择结构

    一.选择结构大纲 if单选择结构 if双选择结构 if多选择结构 嵌套的if结构 switch多选择结构 二.if单选择结构 我们很多时候需要去判断一个东西是否可行,然后我们才去执行,这样一个过程在程序中用if语句来表示 语法: if(布尔表达式) { //如果布尔表达式为true将执行的语句 } 三.if双选择结构 那现在有个需求,公司要收购一个软件,成功了,给人支付100万元,失败了,自己找人开发.这样的需求用一个if就搞不定了,我们需要有两个判断,需要一个双选择结构,所以就有了if-els

  • 看完这篇文章获得一些java if优化技巧

    目录 1.if 合并 2.将正常的流程放在函数的主干执行 3.减少if 1. 使用三元运算符表达式 2.使用java8 中流过滤filter ,不使用if 3.使用枚举 4.使用manager 5.使用Consumer 总结: 1.if 合并 使用逻辑运算符进行合并if.简单的if 嵌套可以使用&& 进行合并.简单的if else 并且操作相同可以使用 || 进行合并,优化代码逻辑,增加可读性. 注意:逻辑运算符的截断性,if(a >= 10 || b >= 20) 当a>

  • java策略枚举:消除在项目里大批量使用if-else的优雅姿势

    想起刚开始接触JAVA面向对象编程时,若遇到大量流程判断语句,几乎满屏都是if-else语句,多得让自己都忘了哪里是头,哪里是尾,但是,纵然满屏是if-else,但彼时也没有觉得多别扭.等到编程能力渐渐提升之后,再回过头去看曾经写过的满屏if-else时,脑海里只有一个画面,全都是翔..... 可能初学者都会忽略掉一点,其实if-else是一种面向过程的实现. 那么,如何避免在面向对象编程里大量使用if-else呢? 网络上有很多解决思路,有工厂模式.策略模式.甚至是规则引擎(这个太重了吧)..

  • 一文了解Java中枚举的使用

    目录 概述 枚举介绍和使用 枚举的本质 枚举常见用途 枚举创建单例 枚举抽象方法 概述 Java中枚举,大家在项目中经常使用吧,主要用来定义一些固定值,在一个有限的集合内,比如在表示一周的某一天,一年中的四季等.那你了解枚举的本质吗?了解枚举的一些常见用法吗? 枚举介绍和使用 枚举主要用来定义一个有限集合内的固定值. 枚举定义方式如下: // 简单的定义 enum WeekEnum { MONDAY, TUESDAY } // 有属性的定义 enum StatusEnum { ENABLE("1

  • java ant 配置及构建项目图文教程

    Ant是一种基于Java的构建工具.Ant文件是配置构建目标过程的XML文件,也称为Ant脚本.(因为对这个不是很了解,所以用词方面可能于个人的理解有偏差,谢谢指出) 如何配置Ant工具呢?下面分步骤说明:1.  下载一个java ant 开发工具,解压到相应的磁盘    例如版本:apache-ant-1.8.2-bin.tar.zip:已上传资源 2. 打开命令行,开始--- 运行----cmd --回车,然后输入ant,它会有提示说这个不是内部文件的字样.这时候用到第三部配置环境 3. 右

  • java中ssj框架的项目搭建流程

    1.新建一个maven项目 2.在pom.xml中,配置所需的jar包及其版本号 <!-- 设置自定义属性和值 --> <properties> <spring.version>4.1.7.RELEASE</spring.version> <hibernate.version>4.3.11.Final</hibernate.version> </properties> <dependencies> <!-

  • Java策略模式实现简单购物车功能

    策略模式是一种行为模式.用于某一个具体的项目有多个可供选择的算法策略,客户端在其运行时根据不同需求决定使用某一具体算法策略. 策略模式也被称作政策模式.实现过程为,首先定义不同的算法策略,然后客户端把算法策略作为它的一个参数.使用这种模式最好的例子是Collection.sort()方法了,它使用Comparator对象作为参数.根据Comparator接口不同实现,对象会被不同的方法排序. 本文例子是,完成一个简单地购物车,两种付款策略可供选择,一为信用卡,另外一种为Paypal. 首先创建策

  • Java如何通过Maven管理项目依赖

    项目的依赖 Java最大的一个优势之一应该是整个生态中无数的框架和API,我们创建实际的项目不可避免的都需要用到这些框架和API,而它们通常都是以JAR包的形式提供.我们之前在编译项目的时候,需要在classpath上存放依赖的JAR包.而且这些外部的JAR包还会有其他依赖.我们需要递归地一个个去下载所有这些外部依赖,并且要确保下载的版本都是正确的,当项目越来越复杂的时候,这是极其麻烦的事情,比如碰到JAR Hell的问题. Maven现在来拯救我们了,Maven可以自动帮我们做依赖管理,我们需

  • Java使用lombok消除冗余代码的方法步骤

    一.项目背景 在写Java程序的时候经常会遇到如下情形: 新建了一个Class类,然后在其中设置了几个字段,最后还需要花费很多时间来建立getter和setter方法. lombok项目的产生就是为了省去我们手动创建getter和setter方法的麻烦,它能够在我们编译源码的时候自动帮我们生成getter和setter方法.即它最终能够达到的效果是:在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法. 比如源码文件: import java.

  • 浅谈HBase在SpringBoot项目里的应用(含HBaseUtil工具类)

    背景: 项目这两个月开始使用HBase来读写数据,网上现成的HBase工具类要么版本混杂,要么只是Demo级别的简单实现,各方面都不完善: 而且我发现HBase查询有很多种方式,首先大方向上有 Get 和 Scan两种,其次行键.列族.列名(限定符).列值(value).时间戳版本等多种组合条件,还有各种过滤器的选择,协处理器的应用,所以必须根据自己项目需求和HBase行列设计来自定义HBase工具类和实现类! 经过我自己的研究整理,在此分享下初步的实现方案吧 ~ 注:HBase版本:1.3.0

  • Java中枚举的实现原理介绍

    目录 基本概述 使用方式 条件选择 循环遍历 集合映射 常用方法 总结 基本概述 在 JDK1.5 之前,通过定义常量使用的都是:public static fianl.而枚举的设计,就是把相关的常量分组到一个枚举类型里,方便创建和管理. 比如我们要定义一个颜色常量: public enum Colour { RED, YELLOW, BLUE, GREEN } 这段代码通过底层编译后,实际创建了4个枚举对象: new Enum<EnumTest>("RED", 0); n

随机推荐