Enum na sterydach

Każdy kto miał okazję programować w Javie i C#, zapewne zwrócił uwagę na subtelną różnicę między tym, co oferują nam typy wyliczeniowe w obu językach. Jeżeli chodzi o C#, nie ma tu wielkiej filozofii. Mamy możliwość zdefiniowania zbioru elementów i ewentualnie przypisania im odpowiedniej wartości liczbowej. W Javie mamy znacznie większe pole manewru. Dozwolone jest tutaj definiowanie pól i metod, tak jak w zwykłej klasie.

Osoby mające już jakieś doświadczenie związane z programowaniem w Javie i wkraczające dopiero w świat C#, mogą czuć się nieco rozczarowane ograniczonymi możliwościami. Z drugiej strony niektórzy programiści C# mogą z zazdrością spoglądać na to co oferuje konkurencyjny język. Bez obaw. C# jest na tyle elestyczny, że bardzo podobny lub nawet ten sam efekt możemy osiągnąć w bardzo prosty sposób. Znane są mi dwie metody, które postaram się krótko przedstawić w dzisiejszym poście.

1. Extension method + atrybuty

Extension method daje nam dużą elastyczność. Możemy dodawać nowe metody do już istniejących, zdefiniowanych w zupełnie innym miejscu typów. To samo możemy zrobić z typem wyliczeniowym, jednakże akurat w tym przypadku jesteśmy nieco ograniczeni. Zazwyczaj nasze oczekiwanie będzie takie, że metoda zwróci inny wynik dla różnych wartości enuma. To oznacza, że w którymś miejscu będzie trzeba wprowadzić switcha obsługującego wszystkie możliwe przypadki. Jest to dość niewygodne rozwiązanie. Za każdym razem kiedy dodamy nową wartość trzeba zaktualizować wszystkie takie miejsca. Z doświadczenia wiem, że o takich rzeczach niestety z czasem się zapomina. Poniżej przykład takiego rozwiązania.

Aby rozwiązać ten problem najlepiej jest skorzystać z atrybutów. Na każdy z elementów enuma możemy nałożyć dowolną liczbę różnych atrybutów. Każdy z nich przechowuje jakąś informację o konkretnym elemencie, co możemy w powodzeniem wykorzystać w extension method. Poniżej przykład tego samego rozwiązania uzupełnionego o atrybuty.

Moim zdaniem jest to znacznie lepsze i bardziej eleganckie rozwiązanie. Pozbywamy się potrzeby stosowania switchów lub if’ów w każdej metodzie rozszerzającej i sprawiamy, że cała konfiguracja znajduje się w jednym miejscu. Bez trudu możemy dodawać kolejne metody i odpowiednie atrybuty.

2. Klasa à la enum

W drugim podejściu rezygnujemy z użycia typu wyliczeniowego oferowanego przez C#. Zamiast tego tworzymy klasę, która będzie pełnić identyczną rolę. Dużą zaletą jest tutaj szeroki wachlarz możliwości. Z kodem możemy działać tak jak ze zwykłym typem. Z drugiej strony – nie dostajemy tego wszystkiego, co w przypadku zwykłego enuma mamy na dzień dobry (np. parsowanie lub inne dobrodziejstwa dostarczane przez klasę System.Enum).  No ale przecież wszystko da się zaimplementować samemu. Pytanie tylko – czy w naszym konkretnym przypadku ma to sens. Kiedyś pomyślałem – a czy nie lepiej po prostu stworzyć klasę dziedziczącą po System.Enum, tak aby nie pozbywać się gotowej implementacji? Oczywiście, że byłoby super. Niestety, kompilator nam na to nie pozwoli 🙂 Poniżej jest przykład analogicznego typu wyliczeniowego, stworzonego tym razem za pomocą klasy.

Oba rozwiązania mają swoje wady i zalety. Przed wyborem jedngo z nich zawsze warto zastanowić się jeszcze raz, czy to czego potrzebujemy to rzeczywiście typ wyliczeniowy czy może jednak coś bardziej złożonego. Mam nadzieję, że ten post okaże się Wam pomocny jeżeli zajdzie odpowiednia potrzeba.

Jeden komentarz dotyczący “Enum na sterydach

  1. Przykład z Extension method i atrybutami bardzo fajny 😉 Na pewno lepsze to niż switche, które są używane chyba najczęściej w takich przypadkach. Co do rozwiązania klasa a’la enum to właśnie tak rozwiązywało się ten problem przed powstaniem Enumów. W którejś z książek pisze o tym m.in. Bob Martin (wujek Bob), że jest to rozwiązanie starszych programistów i żeby jednak od tego odchodzić na rzecz enumów, bo to legacy code 😉

Dodaj komentarz

Twój adres email nie będzie opublikowany. Pola wymagane zostały oznaczone *