SOLID: Single-Responsibility Principle (Zasada pojedynczej odpowiedzialności)

SOLID, czyli 5 zasad projektowania obiektowego

Wprowadzenie

W programowaniu obiektowym klasy są elementami składowymi każdej aplikacji. Jeśli te bloki nie są “solidne” to cała nasza aplikacja może w przyszłości zmagać się z wieloma problemami – zarówno w fazie deweloperskiej jak i produkcyjnej.
Zestaw dobrze zaprojektowanych klas może bardzo przyspieszyć proces kodowania aplikacji, jednocześnie zmniejszając prawdopodobieństwo występowania błędów, np. podczas wdrażania nowych funkcjonalności, rozbudowy aplikacji.
Aby dobrze zaprojektować i napisać aplikację, z pomocą przychodzi nam SOLID, który jest akronimem pięciu najbardziej polecanych zasad projektowania, o których powinniśmy pamiętać podczas pisania kodu.

Wyróżniamy 5 zasad SOLID:

  • Zasada pojedynczej odpowiedzialności (ang. Single-Responsibility Principle – SRP),
  • Zasada otwarte – zamknięte (ang. Open/Closed Principle – OCP),
  • Zasada podstawiania Liskov (ang. Liskov Substitution Principle – LSP),
  • Zasada segregacji interfejsów (ang. Interface Segregation Principle – ISP),
  • Zasada odwracania zależności (ang. Dependency Inversion Principle – DIP).

W poniższym artykule poznamy pierwszą z zasad SOLID – Zasadę Pojedynczej Odpowiedzialności.

SRP – Single Responsibility Principle (Zasada pojedynczej odpowiedzialności)

 

"Jedna klasa powinna mieć jedną i tylko jedną odpowiedzialność."

Zasada SRP mówi, że powinniśmy pisać i utrzymywać daną klasę tylko w jednym celu. Klasa jest kontenerem, do którego możemy dodać dowolną ilość pól i metod – powinniśmy jednak pamiętać, że jeśli będziemy chcieli zawrzeć w jednej klasie zbyt wiele funkcjonalności, to stanie się ona nieporęczna i sprawiać będzie wiele problemów podczas np. rozbudowy aplikacji, czy też testowania.
Jeśli zastosujemy się do zasady SRP, klasy stają się zwarte a jednocześnie elastyczne i łatwe w utrzymaniu. Spójrzmy na przykład.

Przykład zastosowania

//przykład łamiący zasadę SRP

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class User {

    private final String name;
    private final String surname;
    private final String email;

    public User(String name, String surname, String email) throws Exception {
        this.name = name;
        this.surname = surname;
        this.email = validateEmail(email);
    }

    private String validateEmail(String email) throws Exception {
        String regex = "^[A-Za-z0-9+_.-]+@(.+)$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);

        if (!matcher.matches()) {
            throw new Exception("Invalid email address.");
        }

        return email;
    }
} 

W powyższym przykładzie widzimy, że na początku klasa User posiadała dwie odpowiedzialności – pierwszą z nich był model odzwierciedlający rzeczywistego użytkownika, druga odpowiedzialność to walidacja adresu email – która na pewno nie powinna się tam znajdować.
Spróbujmy zrefaktoryzować kod, stosując się do pierwszej zasady SOLID.

//przykład z uwzględnieniem zasady SRP

public class User {
    private final String name;
    private final String surname;
    private final String email;
    private final EmailValidator emailValidator;


    public User(String name, String surname, String email) throws Exception {
        this.emailValidator = new EmailValidator();
        this.name = name;
        this.surname = surname;
        this.email = emailValidator.validateEmail(email);
    }
}


import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EmailValidator {

    public String validateEmail(String email) throws Exception {
        String regex = "^[A-Za-z0-9+_.-]+@(.+)$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);

        if (!matcher.matches()) {
            throw new Exception("Invalid email address.");
        }

        return email;
    }
} 

Stosując się do zasady pojedynczej odpowiedzialności wyodrębniamy walidację adresu do osobnej klasy, dzięki czemu, każda z klas rozwiązuje teraz tylko jeden problem, a zmiana w jednej z nich nie powoduje konieczności wprowadzania zmian w drugiej klasie.

Podsumowanie

Korzystanie z zasady SRP nie oznacza, że klasa powinna mieć tylko jedną publiczną metodę i wykonywać tylko jedną rzecz – powinna jednak mieć tylko jeden powód do zmiany. Jeśli klasa odpowiedzialna będzie tylko za jedną funkcjonalność, za jednej problem, w przypadku wprowadzenia w niej modyfikacji, zmiany takie nie będą pociągać za sobą konieczności wprowadzania zmian w innych klasach.
Warto również dodać, że zasada ta nie odnosi się tylko do klas – warto stosować ją również w odniesieniu do komponentów, modułów czy bibliotek. Zasada pojedynczej odpowiedzialności sprawia, że nie tylko nasze klasy są lepiej zaprojektowane, ale także cała struktura naszej aplikacji.
 
Zapraszam do zapoznania się z pozostałymi zasadami SOLID:
 

Leave a Comment

Your email address will not be published. Required fields are marked *