2008-12-04 57 views
5

假設你保持最初公佈年前的API(Java之前獲得enum支持),它定義了枚舉值一類爲int:當一個API發展時,處理「int enum」模式與java枚舉共存的最佳方式是什麼?

public class VitaminType { 
public static final int RETINOL = 0; 
public static final int THIAMIN = 1; 
public static final int RIBOFLAVIN = 2; 
} 

多年來的API已經演變並獲得了Java的5特有的功能(基因接口等)。現在,你要添加一個新的枚舉:

public enum NutrientType { 
AMINO_ACID, SATURATED_FAT, UNSATURATED_FAT, CARBOHYDRATE; 
} 

的「老式」 INT-枚舉圖案不具有類型安全,無添加的行爲或數據的可能性等,但它的發佈和使用 。我擔心混合兩種樣式的枚舉對API的用戶不一致。

我看到三種可能的途徑:

  • 放棄和(在我虛構的例子NutrientType)定義新的枚舉爲一系列像VitaminType類整數的。你得到一致性,但你沒有利用類型安全和其他現代功能。

  • 決定與矛盾過上公佈的API中:保持VitaminType各地原樣,並添加NutrientType作爲enum。採用VitaminType的方法仍然被聲明爲接受int,那麼採用NutrientType的方法被聲明爲採用這種方法。

  • 擯棄VitaminType課程,並引入新的VitaminType2 enum。將新的NutrientType定義爲枚舉。
    祝賀,對未來2 - 3年,直到你能殺了不推薦使用的類型,你要對付的是花了VitaminType爲int每個單獨的方法不建議使用的版本,並增加了新的foo(VitaminType2 v)每個版本的。您還需要爲每個已棄用的foo(int v)方法以及相應的foo(VitaminType2 v)方法編寫測試,因此您只需將您的QA工作量增加一倍。

什麼是最好的方法?

回答

3

個人意見是,它可能不值得嘗試轉換的努力。首先,「公共靜態最終整數」成語不會很快消失,因爲它在整個JDK中被廣泛使用。另一個原因是,跟蹤下來,原本整數的用法很可能是非常令人不快的,因爲你的類將編譯掉的參考,所以你很可能不知道你已經打破什麼,直到爲時已晚 (我指的是

class A 
    { 
     public static final int MY_CONSTANT=1 
    } 

    class B 
    { 
      .... 
      i+=A.MY_CONSTANT; 
    } 

得到,如果你重寫你可能沒有以往任何時候都意識到,直到你重新編譯B中B被打破編譯成

i+=1 

所以後來。

這是一個非常著名的成語,恐怕不是那麼可怕的把它留下來,證明比替代方案更好。

1

有傳言說的「做」的創作者意識到,生成文件的語法很糟糕,但覺得他不能改變它,因爲他已經有10個用戶。

不惜一切代價向後兼容,即使它傷害了你的客戶,也是一件壞事。 SO並不能真正給你一個明確的答案,但你一定要考慮用戶的長期成本。

也想想你可以重構你的代碼核心的方式將保留舊的基於整數的枚舉僅在外層。

0

最好的是,如果你可以只修復公佈的版本,如果可能的話。在我看來,一致性將是最好的解決方案,所以你需要做一些重構。我個人不喜歡被棄用的東西,因爲他們會陷入困境。您可能會等到更大的版本發佈並在那之前使用這些整數,然後重構大項目中的所有內容。如果這是不可能的,你可能會認爲自己陷入了整數,除非你創建了一些類型的包裝或其他東西。

如果沒有幫助,但你還是進化的代碼,你最終失去一致性或已過時的版本住。無論如何,通常至少在某個時間點,人們會厭倦舊的東西,如果它失去了一致性並從頭創建新的東西......那麼無論如何你都會在未來進行重構。

的客戶可能會放棄該項目,併購買其他產品,如果出現錯誤。通常情況下,客戶的問題不是你能否承受重構,他們只是購買適合他們的產品。所以最終這是一個棘手的問題,需要注意。

1

等待下一個主要修訂,將所有內容都改爲枚舉並提供一個腳本(sed,perl,Java,Groovy,...)以將現有源代碼轉換爲使用新語法。

顯然,這有兩個缺點:

  • 沒有二進制兼容性。這個是多麼重要取決於用例,但在新的主要版本中可以接受
  • 用戶必須做一些工作。如果工作很簡單,那麼這也可以接受。

同時,添加新類型作爲枚舉並將舊類型保存爲整數。

6

API消費者可能會將維生素類型與營養素類型混淆的可能性有多大?如果不太可能,那麼可能最好保持API設計的一致性,特別是如果用戶羣已經建立並且想要最大限度地減少客戶所需的工作/學習差異。如果混亂是有可能的,那麼NutrientType也許應該成爲一個枚舉

這不一定是一個批發一夜之間改變;例如,可以通過枚舉揭露了舊INT值:

public enum Vitamin { 

    RETINOL(0), THIAMIN(1), RIBOFLAVIN(2); 

    private final int intValue; 

    Vitamin(int n) { 
     intValue = n; 
    } 

    public int getVitaminType() { 
     return intValue; 
    } 

    public static Vitamin asVitamin(int intValue) { 
     for (Vitamin vitamin : Vitamin.values()) { 
      if (intValue == vitamin.getVitaminType()) { 
       return vitamin; 
      } 
     } 
     throw new IllegalArgumentException(); 
    } 

} 

/** Use foo.Vitamin instead */ 
@Deprecated 
public class VitaminType { 

    public static final int RETINOL = Vitamin.RETINOL.getVitaminType(); 
    public static final int THIAMIN = Vitamin.THIAMIN.getVitaminType(); 
    public static final int RIBOFLAVIN = Vitamin.RIBOFLAVIN.getVitaminType(); 

} 

這樣就可以更新API,並且用戶可以當棄用舊類型以及調度所述開關懸停在任何代碼中的一些控制該在內部依靠舊的類型。

需要注意保持字面值與那些可能與舊消費者代碼一致的字面值。

相關問題