Java枚舉,酷! (原文發表於2006-04-25 下午01:13:48)

當我頭一次看到Java 5中的新登場的枚舉類型(譯註:enum)時,我還是持懷疑態度的。這些枚舉類型允許你定義成員和方法(譯註:variables and methods)甚至是抽象方法!你能用它來做什麼呢?嗯,我現在已經找到了這個問題的答案。(至少是部分的)

在評閱和改進外面的一些源碼的過程中,我有機會找到了一組用來代表月份的私有靜態常量(譯註:static final constants),並把他們轉換成了Month枚舉。起初,這個Month枚舉僅僅是個簡單的枚舉,但隨着我進一步改進這些源碼時,我發現了越來越多的操作月份常量的方法,或者說,是一些與月份常量緊密關聯的方法。每次我發現一個就把它放到Month枚舉之中。結果如下:

import java.text.DateFormatSymbols;
public enum Month {
  JANUARY(1), FEBRUARY(2), MARCH(3),
  APRIL(4),   MAY(5),      JUNE(6),
  JULY(7),    AUGUST(8),   SEPTEMBER(9),
  OCTOBER(10),NOVEMBER(11),DECEMBER(12);

  private static DateFormatSymbols dateFormatSymbols = new DateFormatSymbols();
  private static final int[] LAST_DAY_OF_MONTH =
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

  public int index;

  Month(int index) {
    this.index = index;
  }

  public static Month make(int monthIndex) {
    for (Month m : Month.values()) {
      if (m.index == monthIndex)
        return m;
    }
    throw new IllegalArgumentException("Invalid month index " + monthIndex);
  }

  public int lastDay() {
    return LAST_DAY_OF_MONTH[index];
  }

  public int quarter() {
    return 1 + (index - 1) / 3;
  }

  public String toString() {
    return dateFormatSymbols.getMonths()[index - 1];
  }

  public String toShortString() {
    return dateFormatSymbols.getShortMonths()[index - 1];
  }

  public static Month parse(String s) {
    s = s.trim();
    for (Month m : Month.values())
      if (m.matches(s))
        return m;

    try {
      return make(Integer.parseInt(s));
    }
    catch (NumberFormatException e) {}
    throw new IllegalArgumentException("Invalid month " + s);
  }

  private boolean matches(String s) {
    return s.equalsIgnoreCase(toString()) ||
           s.equalsIgnoreCase(toShortString());
  }
}

我發現這很值得注意,也很有用。現在我就可像這樣來描述事情:

Month m = Month.parse(inputString);

或是

Month m...;

int lastDay = m.lastDay();

Java 5的枚舉並不定義常量,它們在一個類之中定義了單例(譯註1)對象。有一個類叫Month,還有另外一個代表JANUARY的類從Month派生。這個JANUARY類有唯一的一個單例叫JANUARY。這個JANUARY類的單例就是JANUARY的枚舉對象。

事實上,枚舉是一種創建單例類的方法。每個枚舉對象決不會擁有超過一個的實例,而且這個實例在枚舉被使用之前(可能在加載過程中)就被構建了。而現在枚舉對象就是一些類,它們充滿着類天生的各種技能。下次你再想要單例的時候考慮一下這個:

enum Database {

INSTANCE;

public void open() {...}

...

}

你可以像這樣來使用它:

Database.INSTANCE.open(...);

  

譯註:

1,單例,原文singleton,一種常用的設計模式,詳細介紹可參見uncle bob的著作《敏捷軟件開發:原則、模式與實踐》一書。

 

 (原文鏈接網址:http://www.butunclebob.com/ArticleS.UncleBob.JavaEnums; Robert C. Martin的英文blog網址: http://www.butunclebob.com/ArticleS.UncleBob 

作者簡介:Robert C. MartinObject Mentor公司總裁,面向對象設計、模式、UML、敏捷方法學和極限編程領域內的資深顧問。他不僅是Jolt獲獎圖書《敏捷軟件開發:原則、模式與實踐》(中文版)(《敏捷軟件開發》(英文影印版))的作者,還是暢銷書Designing Object-Oriented C++ Applications Using the Booch Method的作者。MartinPattern Languages of Program Design 3More C++ Gems的主編,並與James Newkirk合著了XP in Practice。他是國際程序員大會上著名的發言人,並在C++ Report雜誌擔任過4年的編輯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章