Even i Odd, czyli DRY in Action 2
Przeglądam ostatnio jakiś stary moduł do softu, który piszę. Trafiłem na ciekawy przypadek złamania zasady DRY. W poprzednim wpisie opisałem czym jest ta zasada. Dla przypomnienia DRY, czyli skrót od angielskiego Don’t Repeat Yourself jest zasadą dobrego programowania, która mówi, żeby unikać powtórzeń kodu. Pozwala to na lepsze zarządzanie kodem (dokładnie zmianą kodu) i tym samym lżejsze życie programistów i supportu.
Dość częstym błędem związanym z DRY jest przetwarzanie warunkowe z powtórzeniem kodu. koronnym przypadkiem jest kolorowanie wierszy parzystych i nieparzystych. Poniżej bardzo zły kod wykonujący to zadanie.
Listing 1. Zły pomysł
if (lp % 2 == 0) {
_lpLbl.setStyleName("result-table-even");
_clrrunLbl.setStyleName("result-table-even");
_clrdayLbl.setStyleName("result-table-even");
_brnorgidtLbl.setStyleName("result-table-even");
_brnrcvidtLbl.setStyleName("result-table-even");
_msgsubgrpLbl.setStyleName("result-table-even");
_doktypLbl.setStyleName("result-table-even");
_pointerLbl.setStyleName("result-table-even");
_msgvolLbl.setStyleName("result-table-even");
_msgvalLbl.setStyleName("result-table-even");
} else {
_lpLbl.setStyleName("result-table-odd");
_clrrunLbl.setStyleName("result-table-odd");
_clrdayLbl.setStyleName("result-table-odd");
_brnorgidtLbl.setStyleName("result-table-odd");
_brnrcvidtLbl.setStyleName("result-table-odd");
_msgsubgrpLbl.setStyleName("result-table-odd");
_doktypLbl.setStyleName("result-table-odd");
_pointerLbl.setStyleName("result-table-odd");
_msgvolLbl.setStyleName("result-table-odd");
_msgvalLbl.setStyleName("result-table-odd");
}
Znacznie prostszym rozwiązaniem w tym przypadku jest użycie zmiennej lokalnej:
Listing 2. Lepsze rozwiązanie
String el = lp % 2 == 0 ? "even" : "odd";
_lpLbl.setStyleName("result-table-" + el);
_clrrunLbl.setStyleName("result-table-" + el);
_clrdayLbl.setStyleName("result-table-" + el);
_brnorgidtLbl.setStyleName("result-table-" + el);
_brnrcvidtLbl.setStyleName("result-table-" + el);
_msgsubgrpLbl.setStyleName("result-table-" + el);
_doktypLbl.setStyleName("result-table-" + el);
_pointerLbl.setStyleName("result-table-" + el);
_msgvolLbl.setStyleName("result-table-" + el);
_msgvalLbl.setStyleName("result-table-" + el);
Dlaczego nie Strategia
Jeszcze lepszym rozwiązaniem jest użycie wzorca strategii. Z drugiej strony jeżeli mamy problem w którym warunek ma naturę binarną to wprowadzanie dodatkowego wzorca projektowego jest tylko niepotrzebnym komplikowaniem kodu. Jeżeli warunek trzeba by było rozszerzyć dla np. 3 rodzajów rekordów to dopiero w tym momencie należy wprowadzić dodatkowy wzorzec.