1. 程式人生 > >Java列舉的使用以及幾種解決if else引起的程式碼不可維護的方案

Java列舉的使用以及幾種解決if else引起的程式碼不可維護的方案

在說列舉之前先來舉個例子,我們都知道發表的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;
    }
}

//實際的業務程式碼
從資料庫獲取state
EnumState 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吧