2011-10-24 6 views
15

私はよく見て、このような表示名または説明を提供するなど、いくつかの基本的なことを行うに取り付けた属性を持つ列挙型を使用しました:"不変のリッチオブジェクトとしての列挙":これは反パターンですか?

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

これは言語の「乱用」と見なすことができます。ほとんどの場合、例えば、保証されていないときは常に 'dynamic'を使用しています。 – Kit

+1

正確に言えば(これはコメントですが)、しかし、私は属性に表示されるテキストをエンコードすることに不安を抱いています。一つ目は、「懸念の分離」に大いに違反していると思いますし、別の問題については、それをローカライズする明白な方法はありません。悲しいかな、MSはこのようなことを奨励しているようですので、昼食に出かけるかもしれません。 –

答えて

6

属性の宣言とアクセスの言語サポートが非常に不十分であるため、これはC#の貧弱なパターンと考えられます。彼らは非常に多くのデータを格納することを意図していません。些細でない値で属性を宣言するのは苦痛であり、属性の値を得るのは苦痛です。あなたのenumに関連付けられた興味深いもの(enum上の何かを計算するメソッドや、非プリミティブなデータ型を含む属性のようなもの)が必要な場合は、それをクラスにリファクタリングするか、または他のものをいくつかの帯域外の場所。

同じ情報を持つ静的インスタンスを持つ不変クラスを作成することは、それほど難しくありません。私の意見では、それはもっと慣れています。

+0

列挙型の宣言*と不変の豊富なオブジェクトとの間に難しいことはありませんし、豊かな列挙型の実装者には痛みがありますが、*用法はどうですか?あなたのポイント*イディオム*は私とうまく座っていますが。 – Kit

+0

慣用コードの作成についての良い点。あなたは常にそれが住んでいる言語/フレームワークでうまく演奏するコードを書いています。 – FMM

5

私はそれが反パターンだと思います。理由は次のとおりです。既存の列挙型(ここでは簡潔にするために属性を取り除く)を取ってみましょう:

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

ここで、必要性がもう少し正確になるように拡大してみましょう。 2にあなたの「疑似クラス」の一つの「フィールド」を回し、見出しおよび/または速度の変化を言う:

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

だから、あなたは今、不変なクラスに変換する必要が成文化された列挙型を持っていますなぜなら、あなたは今、同じインターフェースで本当に一緒に属している2つの直交した(しかし変わらない)プロパティを追跡しているからです。あなたの "豊かな列挙型"に対して書いたコードは、今や大量に掘り下げて再加工する必要があります。一方、クラスとして始めるのであれば、やるべき仕事が少なくなるでしょう。

時間が経つにつれてコードがどのように維持されるのか、豊富な列挙型がクラスよりも保守性が高くなるのかどうか尋ねる必要があります。私の賭けは、それがより保守的ではないということです。また、mquanderが指摘しているように、クラスベースのアプローチはC#ではもっと慣れています。

他にも何かを考慮する必要があります。オブジェクトが不変で、classではなくstructである場合、列挙型と同じように、値渡しのセマンティクスとオブジェクトの直列化サイズと実行時サイズの差は無視できます。

+0

これまでに私はこの問題に遭遇しましたが、それ以上は同意できません。 –

関連する問題