Refaktoryzacja w praktyce – zastąpienie instrukcji switch wzorcem State

Instrukcje switch, choć na pozór niegroźne, mogą okazać się trudne w utrzymaniu i prowadzić do prostych błędów. Jeżeli mamy w kodzie wiele instrukcji switch opartych na jakimś enumie, w przypadku rozszerzenia tego enuma, musimy dokonać zmian we wszystkich miejscach gdzie te instrukcje występują. Zabiera to oczywiście czas, a dodatkowo łatwo, któreś z tych miejsc pominąć.

Załóżmy, że mamy klasę pracownika, która wygląda następująco:

Mamy tutaj kilka standardowych właściwości jak imię, nazwisko, pensja itp. Dodatkowo mamy typ pracownika, który określa zajmowane przez niego stanowisko:

Klasa posiada także trzy metody, które wykonują różne operacje zależnie od tego z jakiego typu pracownikiem (na jakim stanowisku), mamy do czynienia. Przykładowo metoda obliczająca premie ma inny mnożnik w zależności od zajmowanego stanowiska. W przypadku dodania kolejnego stanowiska, musimy rozszerzyć wszystkie instrukcje switch, co w przypadku ich większej ilości może być kłopotliwe zwłaszcza, jeżeli okaże się, że są one rozsiane po różnych klasach czy projektach. Ponadto wygląda to mało elegancko, choćby ze względu na redundancję kodu.

W pierwszej chwili dobrym rozwiązaniem problemu może się wydawać dziedziczenie i stworzenie osobnej klasy dla każdego typu pracownika, która dziedziczyłaby po klasie Employee i nadpisywała te trzy metody. Trzeba jednak wziąć pod uwagę, że typ jest czymś zmiennym. Programista np. może awansować na Team Leader’a.

Możemy zatem potraktować typ pracownika jako pewnego rodzaju zmienny stan i zastosować wzorzec stanu (State Pattern). Zaczniemy od utworzenia interfejsu dla stanu, który będzie zawierał te trzy metody, które chcemy zrefaktoryzować:

Następnie utwórzmy konkretną implementacje tego interfejsu dla managera:

Analogicznie dla pozostałych typów (stanowisk). Pozostało tylko dokonać kilku zmian w klasie Employee, która wygląda teraz następująco:

 

Jak widać zostało dodane prywatne pole _employeeState o typie utworzonego przez nas interfejsu. Podczas zmiany typu zaktualizowana zostaje wartość tego pola poprzez przypisanie do niego konkretnej implementacji tego interfejsu zależnie od ustawionego stanu. Natomiast instrukcje switch we wszystkich trzech metodach zostały zastąpione wywołaniem odpowiedniej metody z klasy stanu. W ten sposób udało się zredukować 3 instrukcje switch do jednej.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *