Java枚举的使用以及几种解决if else引起的代码不可维护的方案

来源:互联网 发布:常州口腔医院挂号软件 编辑:程序博客网 时间:2024/06/06 07:44

在说枚举之前先来举个例子,我们都知道发表的csdn博客都需要审核,那么审核的状态就有这么几种:审核中、审核通过、审核不通过(假设目前的需求就要求有这么三种状态)。那么我们可以在项目里这么写

if(state == 1){            //1表示审核中    MethodA();}else if(state == 2){      //2表示审核通过    MethodB();}else if(state == 3){      //3表示审核不通过    MethodC();}

但是这样的硬编码只是图个方便,还是有很大的问题的。万一哪天需要改变状态的标识,用0来表示审核不通过,或者需求改变,需要增加、删除状态的时候,那就不得不改变所有与审核状态有关的代码,这个工作量无疑是巨大的,如果是庞大的项目,肯定是会有遗漏的。

好,既然这种硬编码不行,我们很快就能想到用静态常量(或者用配置文件)来表示审核的状态

public static final int AUDITING = 1;   //审核中public static final int AUDIT = 2;      //审核通过public static final int UNAUDIT = 3;    //审核不通过if(state == AUDITING){    MethodA();}else if(state == AUDIT){    MethodB();}else if(state == UNAUDIT){          MethodC();}

这样的写法很好的解决了改变状态标识引发的问题,当标识改变时,只需修改常量类就行,而不用修改整个项目所有涉及到状态标识的地方。但是当项目需求改变,需要新加一种未审核状态,你除了在常量类新加一个变量,还需要在所有的相关代码中加一个else if,这显然也是不科学的。当然,你可以重构你的代码,不使用这种if else来判断你的逻辑。方法还是挺多的,下面就简单介绍几种。

1.使用多态:

//基类:abstract public class Base{    abstract public void method();}//审核中public class Auditing extends Base{    public void method(){        ...    }}//审核通过public class Audit extends Base{    public void method(){        ...    }}//审核不通过public class UnAudit extends Base{    public void method(){        ...    }}//业务功能public static void main(String[] args) {    //从数据库获取状态,并赋给变量state    Base base = match(state);      base.method();  }  private static Base match(int state) {      if(state == AUDITING){        return new Auditing();    }else if(state == AUDIT){        return new Audit();    }else if(state == UNAUDIT){              return new UnAudit();    }  }  

当新加一种状态,只要在match方法中加上具体的逻辑,而不用向之前那样在所有涉及到的地方进行修改。我们可以发现,以上的代码只适合一种业务逻辑,比如说在你的项目中,所有的判断都是根据状态显示不同颜色的:博客状态是审核中的,颜色显示红色,是审核通过的,颜色显示黑色。但是如果在你的项目中有多种业务逻辑,一处逻辑是根据状态显示不同的颜色,一处逻辑是根据状态显示不同的信息,那么以上的代码就不适用了,需要稍加修改。给method方法添加参数来调用不同的业务逻辑。

2.如果多态需要创建的类太多,可以使用枚举:根据不同的状态显示不同的文字和颜色

//枚举类public enum EnumState{    UNMATCH(-1,"不匹配","#FFFFFF"),    AUDITING(1,"审核中","#FFFFFF"),    AUDIT(2,"审核通过","#FFFFF0"),    UNAUDIT(3,"审核未通过","#FFFAFA");    private int identify;    private String wordInfo;    private String color;    EnumState(int identify,String wordInfo,String color){        this.identify = identify;        this.wordInfo = wordInfo;        this.color = color;    }    public static EnumState getState(int state){        for (EnumState eachState : values()) {        if(state == eachState.identify){            return eachState;        }        }        return UNMATCH;     }    public int getIdentify() {        return identify;    }    public void setIdentify(int identify) {        this.identify = identify;    }    public String getWordInfo() {        return wordInfo;    }    public void setWordInfo(String wordInfo) {        this.wordInfo = wordInfo;    }    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }}//实际的业务代码从数据库获取stateEnumState enumState = EnumState.getState(state);

从以上代码可以看出,当需求改变时,我们只需要在枚举类中进行简单修改,而不用在所有涉及到的代码中修改。

其实还有很多方法可以规避大量if else带来的问题,至于用哪种方法还是看你具体使用的场景。在你的项目中仅仅只有一处地方用到了if else,那么用if else又有何不可呢,反正以后需求改变,你也知道去什么地方修改。也有的程序员就是不喜欢用枚举,喜欢用常量,觉得枚举又要消耗性能,又不能继承不能扩展,还是常量用起来简单方便,在不追求代码扩展性,不考虑类型安全的前提下,那就用呗。当然如果在系统升级阶段,需要改变常量值,就要重新编译,在这点上用常量是不如用配置文件或者xml的;相反的,有的程序员就是不喜欢常量,喜欢枚举,又不是有很多地方用到枚举,那么牺牲一点性能换来代码的可维护又何尝不可呢。当用的枚举越来越多,考虑到性能的时候,就要用多态或者其他什么方法来替代枚举

好,现在终于可以步入正题,介绍枚举的使用了。哈哈哈哈哈…

public enum Season{    SPRING,SUMMER,FALL,WINTER;}
  • 这里定义的Season本身是一个类,并且存在四个实例(不是字符串),可以直接打印Season.SPRING这个实例
  • 两个枚举类型的值比较可以直接用“==”,而不是必须用equals
Season s1 = Enum.valueOf(Season.class, "SPRING");Season s2 = Enum.valueOf(Season.class, "SPRING");System.out.println(s1 == s2);   //true
  • 可以在枚举类中添加构造器、方法和域。在这里,这四个实例SPRING,SUMMER,FALL,WINTER已经调用了四次默认的构造函数Season()

  • 非抽象的枚举类默认使用final修饰,因此枚举类不能被继承

  • 枚举类也不能继承其他的类,因为java是单一继承,他已经继承了java.lang.Enum

  • 枚举类是单例的,所以他的构造器默认是private的,也必须是private的(可以不写)

  • 枚举类的所有实例必须在第一行显示列出,并且系统会自动用 public static final修饰

  • 对于枚举类的遍历可以用values()方法,Season []seasons = Season.values(),具体可以参照上面的代码

  • toString:返回枚举常量名。Season.SPRING.toString()将返回字符串”SPRING”

  • valueOf:toString的逆方法,将字符串变为枚举类型

  • ordinal:返回枚举常量在枚举声明中的位置,位置从0开始计数。Season.SPRING.ordinal()返回0

还有其他的方法具体就参考api吧

原创粉丝点击