Code review: Instrukcje warunkowe

W programowaniu obiektowym użycie tak popularnej konstrukcji jak if-else jest często symptomem złej architektury. Załóżmy, że mamy metodę walidującą dostęp do danych np:

private bool Validate(string userName, string password, AuthType authType)
{
    if(authType == AuthType.PlainPwd)
    {
        if(password == _user.Password)
            return true;            
    }
    else if(authType == AuthType.MD5)
    {
        if(Md5.Hash(password) == _user.Password)    
    }
    else if(authType == ....)
    // ITD...

}

Powyższy kod łamie kilka zasad inżynierii oprogramowania np. Open\Closed Principle. Aby dodać nowy typ autoryzacji musimy dodać kolejny element do ENUM oraz zmodyfikować już istniejącą metodę. Przed postawieniem każdego IF’a w programowaniu obiektowym należy się sporo zastanowić. Często IF oznacza złamaną zasadę Open\Closed  i po prostu zapomnienie o polimorfizmie. Dużo lepszym podejściem jest stworzenie interfejsu IValidator a potem różne implementacje typu HotmailValidator, Md5PasswordValidator itp.

Co to zmieni? Dodając nowy typ walidacji, nie musimy modyfikować istniejącego kodu, który został już przetestowany. Dodanie nowej funkcjonalności typu autoryzacja na podstawie ról, także będzie łatwiejsza bo nie będziemy musieli zaśmiecać powyższej metody a kod będziemy mogli umieścić w konkretnej już klasie.

Kolejna sprawa to testy jednostkowe. Dysponując Inversion of Control łatwo będzie podstawić coś w stylu MockValidator. Nie musimy w końcu się łączyć realnym serwerem aby zweryfikować hasło podczas testów.

IF’y nie są elastycznym rozwiązaniem i często kończą się zaśmiecaniem kodu, który na końcu skutkuje spaghetti i długim szukaniem błędów. Sam IF jest często zaprzeczeniem zasady Single responsibility bo jeśli w tej samej klasie mamy różne problemy (concerns) tzn. że logika powinna zostać rozdzielona na więcej klas.

Oczywiście nie można uogólniać. Nie ma nic złego w sprawdzeniu czy parametr funkcji Divide jest różny od zero.  Chodzi raczej o serie IF’ów, np. w funkcji walidującej poprawność danych. Brzydkie rozwiązanie to seria IF’ów sprawdzającą długość, format itp. Poprawne rozwiązanie to np. z użycie wzorca chain of responsibility.

3 thoughts on “Code review: Instrukcje warunkowe”

  1. Przydałby się jeszcze przykład poprawnego rozwiązania opartego o wspomniany interfejs IValidator.

Leave a Reply

Your email address will not be published.