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吧