2011-10-24 78 views
15

我經常看到和使用枚舉附帶的屬性做一些基本的東西,如提供的顯示名稱或說明:「Enum as immutable rich-object」:這是一種反模式嗎?

public enum Movement { 
    [DisplayName("Turned Right")] 
    TurnedRight, 
    [DisplayName("Turned Left")] 
    [Description("Execute 90 degree turn to the left")] 
    TurnedLeft, 
    // ... 
} 

併產生了一套擴展的方法來支持的屬性:

public static string GetDisplayName(this Movement movement) { ... } 
public static Movement GetNextTurn(this Movement movement, ...) { ... } 

遵循此模式,可以將其他現有或自定義屬性應用於字段以執行其他操作。這幾乎是如果枚舉可以作爲簡單枚舉值類型它是,並且與許多領域的更豐富的不可變值對象的工作:

public class Movement 
{ 
    public int Value { get; set; } // i.e. the type backing the enum 
    public string DisplayName { get; set; } 
    public string Description { get; set; } 
    public Movement GetNextTurn(...) { ... } 
    // ... 
} 

通過這種方式,它可以「旅行」作爲一個簡單的在序列化期間,快速比較等,但行爲可以被「內化」(ala OOP)。

這就是說,我認識到這可能被認爲是反模式。同時我的一部分認爲這很有用,因爲可能太嚴格了。

+4

你問在你不會使用枚舉的地方使用這種模式是不是一個好主意?將元數據與枚舉值相關聯是一個很好的模式。這不像代替班級那麼棒。 –

+0

它可以被認爲是「濫用」該語言;幾乎就像在不擔保的情況下一直使用「動態」一樣。 – Kit

+1

不完全在點(因此評論),但我對編碼文本顯示在一個屬性 - 或實體類附近的任何地方,對於這個問題的疑慮。首先,我認爲這嚴重違反了「關注點分離」的問題,另一方面,沒有明確的方法將其本地化。唉,MS似乎鼓勵這樣的事情,所以也許我會出去吃午飯。 –

回答

6

我認爲這是C#中的一個糟糕的模式,僅僅是因爲聲明和訪問屬性的語言支持如此殘缺;它們並不意味着存儲非常多的數據。用非平凡值聲明屬性是一件痛苦的事情,獲得​​屬性值是一件很痛苦的事情。只要你想要一些與你的枚舉相關聯的遠程感興趣的東西(比如在枚舉上計算某些東西的方法,或者包含非基元數據類型的屬性),你需要重構它到一個類或者把其他東西放入一些帶外的地方。

用一些擁有相同信息的靜態實例創建一個不可變類並不難,在我看來,它更具慣用性。

+0

從枚舉的聲明和不可變的富對象的角度來看,這並不困難,對於富枚舉的實現者來說是痛苦的,但是*用法*呢?儘管你對*成語*的觀點與我很好。 – Kit

+0

關於編寫慣用代碼的好處。你總是希望編寫能夠適應其語言/框架的代碼。 – FMM

5

我想說這是一種反模式。這是爲什麼。讓我們現有的枚舉(這裏爲簡便起見剝屬性):

public enum Movement 
{ 
    TurnedRight, 
    TurnedLeft, 
    Stopped, 
    Started 
} 

現在,讓我們說需要擴大是一些更精確;也就是說,在標題和/或速度的變化,你的「僞類」轉向一個「場」爲兩個:

public sealed class Movement 
{ 
    double HeadingDelta { get; private set; } 
    double VelocityDelta { get; private set; } 
    // other methods here 
} 

所以,你已經成文枚舉,現在已經被改造成不可變類因爲你現在正在跟蹤兩個真正屬於同一界面的正交(但仍然是不可變的)屬性。你現在寫的任何對你的「富恩」寫的代碼都必須清理乾淨並重寫;而如果你開始將它作爲一個班級開始,你可能會做更少的工作。

你必須要問,隨着時間的推移如何維護代碼,以及如果豐富的枚舉將比班級更易於維護。我敢打賭,它不會更易於維護。另外,正如mquander指出的那樣,基於類的方法在C#中更具慣用性。

還有其他要考慮的事情。如果對象是不可變的並且是struct而不是class,那麼您將獲得相同的按值傳遞語義並且對象的序列化大小和運行時大小可以忽略不計,就像使用枚舉一樣。

+0

我以前遇到過這種情況,不能同意更多。 –