2013-05-12 20 views
7

Deweloper przy pracy zaczął ostatnio używać wzorca klasy zamiast wyliczania w miejscach, w których zwykle mieściły się wyliczanki. Zamiast tego używa czegoś podobnego do tego poniżej:Kiedy i jak należy używać klas wyliczeniowych zamiast wyliczania?

internal class Suit 
{ 
    public static readonly Suit Hearts = new Suit(); 
    public static readonly Suit Diamonds = new Suit(); 
    public static readonly Suit Spades = new Suit(); 
    public static readonly Suit Clubs = new Suit(); 
    public static readonly Suit Joker = new Suit(); 
    private static Suit() 
    { 

    } 
    public static bool IsMatch(Suit lhs, Suit rhs) 
    { 
     return lhs.Equals(rhs) || (lhs.Equals(Joker) || rhs.Equals(Joker)); 
    } 
} 

Jego rozumowanie jest to, że niewidoczny wygląda wyliczenie, ale pozwala mu zawierać metod związanych z numeracją (jak IsMatch powyżej), aby być zawarty w sama wyliczenie.

Nazwał to klasą wyliczeń, ale nie jest to coś, co kiedykolwiek widziałem. Zastanawiałem się, jakie są zalety i wady i gdzie mogę znaleźć więcej informacji?

Dzięki

Edit: Inną zaletą opisał była możliwość dodania specyficznych toString() wdrażanie do policzenia.

+0

Cóż, nie można tego zrobić za pomocą 'enum' ponieważ nie można wpisać enum do typu złożonego. Domyślam się, że to jest główny powód używania czegoś takiego? –

+0

Jedynym prawdziwym minusem (poza tym, że niektóre biblioteki stron trzecich nie są zbytnio z tego powodu zadowolone), z jakim się zetknąłem, jest to, że nie można (trywialnie) zrobić przełącznika/obudowy na typie. Ale potem nie używałem tej techniki szeroko w języku C#. –

+0

Unikanie instrukcji zmiany było właściwie jego głównym punktem sprzedaży. Użył go, aby uniknąć tego, co opisał jako monolityczne instrukcje przełączające. Chodzi o to, że powstrzymuje cię to przed użyciem, nawet jeśli chcesz. –

Odpowiedz

1

Główną zaletą wyliczeń jest to, że są to w zasadzie liczby całkowite z niektórymi nazwanymi wartościami, jako że są one z natury przenośne i można je szeregować. Operacje arytmetyczne i logiczne są również szybsze w wyliczeniach.

Klasy wyliczeń są używane, gdy potrzebna jest nieprzezroczysta wartość, która zawiera dodatkowe informacje o stanie. Na przykład ogólny Warstwa dostępu do danych może mieć jako interfejs jak:

 
public static class Dal 
{ 
    public static Record Query(Operation operation, Parameters parameters); 
} 

var result = Dal.Query(Operation.DoSomething, new DoSomethingParameters {...}); 

dla użytkowników Operacji Dal jest tylko wyliczenie czynności dostępnych, ale może zawierać ciąg połączenia, instrukcję SQL lub przechowywane procedura i wszelkie inne dane wymagane przez rodzajowy Dal.

Innym "powszechnym" zastosowaniem jest tryb publiczny w systemie (stan lub strategia). Z perspektywy użytkownika tryb jest wartością nieprzezroczystą, ale może zawierać informacje lub funkcje wewnętrzne niezbędne do wdrożenia systemu. Zmyślony przykład:

 

public class TheSystem 
{ 
    public SystemMode Mode; 
    public void Save() 
    { 
     Mode.Save(); 
    } 
    public SystemDocument Read() 
    { 
     return Mode.Read(); 
    } 
} 

public abstract class SystemMode 
{ 
    public static SystemMode ReadOnly = new ReadOnlyMode(); 
    public static SystemMode ReadWrite = new ReadWriteMode(); 

    internal abstract void Save(); 
    internal abstract SystemDocument Read(); 

    private class ReadOnlyMode : SystemMode 
    { 
     internal override void Save() {...} 
     internal override SystemDocument Read() {...} 
    } 

    private class ReadWriteMode : SystemMode 
    { 
     internal override void Save() {...} 
     internal override SystemDocument Read() {...} 
    } 
} 


TheSystem.Mode = SystemMode.ReadOnly; 

Nie sądzę, po prostu mającą IsMatch metoda statyczna warrantów nie stosując proste teksty stałe. W tym przypadku można osiągnąć coś bardzo podobnego dzięki metodom rozszerzania.

+0

Więc są znanym narzędziem, które ma swoje zastosowania, ale nie powinno się go używać wszędzie. Jak większość rzeczy. Dzięki za przykłady. –

1

Wykończenia są idealne dla informacji o niewielkich obciążeniach. Na przykład, wyliczenie kolorów (z wyjątkiem niebieskiego) byłoby dobre dla zapytania o stan sygnalizacji świetlnej. Prawdziwy kolor wraz z całą koncepcją koloru i całego jego bagażu (alfa, przestrzeń kolorów, itp.) Nie ma znaczenia, tylko w jakim stanie jest światło. Również, zmieniając trochę wyliczenie, aby reprezentować stan sygnalizacji świetlnej :

[Flags()] 
public enum LightColors 
{ 
    unknown = 0, 
    red = 1, 
    yellow = 2, 
    green = 4, 
    green_arrow = 8 
} 

Obecny stan światło może być ustawiony jako:

LightColors c = LightColors.red | LightColors.green_arrow; 

I zapytaliśmy jak:

if ((c & LightColors.red) == LightColors.red) 
    { 
     //Don't drive 
    } 
    else if ((c & LightColors.green_arrow) == LightColors.green_arrow) 
    { 
     //Turn 
    } 

statyczne członkowie klasy kolor będzie w stanie obsługiwać tę wielokrotność stan bez dodatkowej funkcjonalności.

Jednak statyczni członkowie klasy są wspaniali dla powszechnie używanych obiektów. Członkowie System.Drawing.Color są świetnymi przykładami, ponieważ reprezentują kolory o znanej nazwie, które mają niejasne konstruktory (chyba że znasz swoje kolory hex).Gdyby były realizowane jako teksty stałe trzeba by zrobić coś takiego za każdym razem chciał użyć wartości jako kolor:

colors c = colors.red; 
     switch (c) 
     { 
      case colors.red: 
       return System.Drawing.Color.FromArgb(255, 0, 0); 
       break; 
      case colors.green: 
       return System.Drawing.Color.FromArgb(0,255,0); 
       break; 
     } 

Więc jeśli masz enum i okaże się, że ciągle robi przełącznika/case/if/else/cokolwiek do wyprowadzenia obiektu, możesz użyć statycznych elementów klasy. Jeśli tylko pytasz o stan czegoś, będę trzymać się wyrażeń. Ponadto, jeśli musisz przekazać dane w niebezpieczny sposób, wyliczenia prawdopodobnie przetrwają lepiej niż seryjna wersja twojego obiektu. tworzą

odniesienie do starego posta z tego forum: When to use enums, and when to replace them with a class with static members?

+0

Ten post bardzo przypomina to, czego szukałem, z dobrym przykładem z frameworka. Dzięki –

4

wyliczenia są dobrze w wielu sytuacjach, ale dość słaba w innych. Zazwyczaj znajdę jakieś problemy z wyliczenia:

  • Zachowanie związane z wyliczeniem dostaje rozrzucone wokół aplikacji
  • Nowe wyliczenie wartości wymagają strzelbą CHIRURGIA
  • Wyliczenia nie przestrzegają Open-Closed Principle

Zachowanie wyliczeniowe wokół, nigdy nie możemy przywrócić go do typu źródła, ponieważ typy wyliczeń nie mogą mieć żadnego zachowania (lub stan).

W drugiej z Wyliczanie klasy:

Wszystkie odmiany każdego typu wyliczenia może być popychany w dół nie tylko do klasy wyliczenia, ale do każdego konkretnego podtypu.

Wyliczenia działają dobrze w różnych scenariuszach, ale mogą szybko się zepsuć w modelu domeny. Klasy wyliczeń zapewniają dużo tej samej użyteczności, z dodatkową korzyścią stania się celem dla zachowania.

Instrukcje przełączania nie są już potrzebne, ponieważ mogę popchnąć tę zmienność i wiedzę tam, gdzie ona należy, z powrotem do modelu. Jeśli z jakiegoś powodu muszę sprawdzić określone wartości klas wyliczeniowych, opcja jest dla mnie wciąż otwarta. Ten wzorzec nie powinien zastępować wszystkich wyliczeń, ale miło mieć alternatywę.

można przeczytać na tej here