SOLID #1 – SRP

Jest to pierwsza część cyklu o mnemoniku SOLID. SOLID jest, krótko mówiąc zbiorem pięciu założeń programowania obiektowego,  finalnie sformułowanych i opisanych przez Roberta C. Martina – wybitnego programistę. Warto zaznaczyć, że reguły na których opiera się SOLID zostały wypracowane przez developerów na przestrzeni lat ale zostały spopularyzowane właśnie przez tego Pana.

 

SOLID

S – Zasada pojedynczej odpowiedzialności (Single Responsibility Principle – SRP)
O – Zasada otwarte – zamknięte – (Open-Closed Principle – OCP)
L – Zasada podstawiania Liskov  – (Liskov Substitution Principle – LSP)
I  – Zasada segregacji interfejsu – (Interface Segregation Principle – ISP)
D – Zasada odwracania zależności – (Dependency Inversion  Principle DIP)

 

Każdą z tych zasad będę przedstawiał w kolejnych częściach cyklu. W tej zajmiemy się pierwszą z nich, czyli zasadą pojedynczej odpowiedzialności. W myśl tej zasady, klasa powinna mieć pojedynczą odpowiedzialność – jeden powód do zmiany.

 

Single Responsibility Principle

Spójrzmy na klasę przedstawioną poniżej:

class BadEmployee
{
    private readonly string _email;
    private readonly int _salary;
    private string _name;
    private string _surname;

    public BadEmployee(string name, string surname, string email, int salary)
    {
        _salary = salary;
        _email = email;
        _name = name;
        _surname = surname;
    }
}

Klasa ta opisuje pracownika. Zawiera imię , nazwisko, wiek oraz adres e-mail. Mając taką klasę, zapewne chcielibyśmy sprawdzać poprawność danych pracownika. Dodajmy zatem metody sprawdzające e-mail oraz to czy np. pracownik zarabia więcej niż 2500zł.

 

class BadEmployee
{
    private readonly string _email;
    private readonly int _salary;
    private readonly int _salaryThreshold = 2500;
    private string _name;
    private string _surname;

    public BadEmployee(string name, string surname, string email, int salary)
    {
        _salary = salary;
        _email = email;
        _name = name;
        _surname = surname;
    }

    private string ValidateEmail()
    {
        string message = string.Empty;

        if (string.IsNullOrWhiteSpace(_email))
            message += "brak emaila, ";

        if (!_email.Contains("@"))
            message += "niepoprawny email, ";


        return message;
    }

    private bool CheckSalary()
    {
        return _salary >= _salaryThreshold;
    }
}

 

W porządku! Mamy pracownika, potrafimy sprawdzić poprawność jego danych. Nie bez powodu nazwałem klasę BadEmployee, bo rzeczywiście jest to zły pracownik. Otwarcie łamie zasadę SRP, ponieważ klasa ta przechowuje dane pracownika oraz jest odpowiedzialna za sprawdzenie poprawności tych danych. Walidacja powinna zostać oddelegowana do innej klasy przez co zasada SRP będzie działać a odpowiedzialności zostaną jasno rozdzielone. Spójrzmy na kod poniżej:

 

class GoodEmployee
{
    private readonly string _email;
    private readonly int _salary;
    private readonly ValidityTool _validityTool;
    private string _name;
    private string _surname;


    public GoodEmployee(string name, string surname, string email, byte salary)
    {
        _salary = salary;
        _email = email;
        _name = name;
        _surname = surname;

        _validityTool = new ValidityTool();
    }

    private string ValidateEmail()
    {
        return _validityTool.ValidateEmail(_email);
    }

    private bool IsAdult()
    {
        return _validityTool.CheckSalary(_salary);
    }
}

class ValidityTool
{
    private readonly int _salaryThreshold = 2500;

    public string ValidateEmail(string email)
    {
        string message = string.Empty;

        if (string.IsNullOrWhiteSpace(email))
            message += "brak emaila, ";

        if (!email.Contains("@"))
            message += "niepoprawna email, ";


        return message;
    }

    public bool CheckSalary(int salary)
    {
        return salary >= _salaryThreshold;
    }
}

 

Dodaliśmy klasę ValidityTool,  która jest odpowiedzialna za sprawdzenie poprawności danych. W klasie dobrego pracownika, oddelegowujemy zadanie walidacji do klasy ValidityTool.  Co zyskaliśmy? Podział odpowiedzialności – każda klasa ma swój jasno określony cel. Klasa GoodEmployee jest typowym przykładem klasy modelu. Tego typu klasy powinny tylko przechowywać dane, natomiast inne zadania (np. walidacja) powinny zostać oddelegowane do innych klas.

 

Na koniec

Należy pamiętać o tym aby tworzone klasy miały jedno jasno określone zadanie. Mimo, że jest to prawdopodobnie najłatwiejsza zasada w mnemoniku SOLID to stosowanie jej jest stosunkowo trudne. Często trudno jest wywnioskować czy napisana klasa rzeczywiście posiada pojedynczą odpowiedzialność. Jednakże wraz ze zdobytym doświadczenie staje się to coraz łatwiejsze.

Mam coś dla Ciebie

Zapisz się do mojego newslettera, a ja prześlę Ci zbiór kilkunastu praktycznych wskazówek dla programisty aplikacji mobilnych.

Menu