Single Responsibility Principle

Single Responsibility Principle – SRP

Zasada pojedynczej odpowiedzialności mówi, że każda klasa, moduł lub funkcja powinny mieć tylko jedno, jasno określone zadanie. W praktyce oznacza to, że każdy komponent w aplikacji powinien odpowiadać tylko za jeden aspekt funkcjonalności systemu.

Dlaczego to jest ważne:

Łatwiejsze utrzymanie: Kod, który przestrzega zasady jednej odpowiedzialności, jest bardziej przejrzysty i łatwiejszy do zrozumienia. Gdy klasa robi tylko jedną rzecz, jej odpowiedzialność jest jednoznaczna, co ułatwia debugowanie i wprowadzanie zmian.

Mniejsza podatność na błędy: Gdy jedna klasa jest odpowiedzialna za zbyt wiele zadań, każda zmiana może wpłynąć na wiele funkcji naraz, co zwiększa ryzyko wprowadzenia błędów. Podział obowiązków redukuje to ryzyko.

Łatwiejsze testowanie: Gdy klasa wykonuje jedno zadanie, testy jednostkowe są bardziej specyficzne i skuteczniejsze. Można testować każdą funkcjonalność oddzielnie.

Przykład z życia:

Remont domu

Podczas remontu domu, różne zadania wymagają różnych specjalistów. Przykładowe zadania to:

  1. Instalacja hydrauliczna: Montaż rur, umywalek, toalet, itp.
  2. Instalacja elektryczna: Montaż przewodów, gniazdek, przełączników, itp.
  3. Malowanie ścian: Przygotowanie powierzchni, malowanie, wykończenie.
  4. Montaż podłóg: Instalacja paneli, desek, kafli itp.
  5. Remont kuchni: Wymiana szafek, blatu, AGD itp.

Każde z tych zadań wymaga innej wiedzy i umiejętności, dlatego w rzeczywistości zatrudniasz różnych specjalistów do każdego z tych zadań:

  1. Hydraulik: Specjalizuje się w instalacjach wodno-kanalizacyjnych. Odpowiada za montaż rur, kranów, umywalek i systemów grzewczych.
  2. Elektryk: Zajmuje się instalacją elektryczną. Montuje przewody, gniazdka, oświetlenie i systemy zabezpieczeń.
  3. Malacz: Specjalizuje się w malowaniu ścian. Przygotowuje powierzchnie, nakłada farby i wykończenia.
  4. Specjalista od podłóg: Montuje różne typy podłóg, w tym panele, kafle i deski.
  5. Stolarz kuchenny: Zajmuje się montażem mebli kuchennych i urządzeń.

Przykład programu przed użyciem zasady SRP:

Wyobraź sobie klasę UserManager, która zarządza użytkownikami i ma wiele zadań:


import java.util.ArrayList;
import java.util.List;

// Klasa łamiąca zasadę SRP
public class UserManager {
    private List<String> users = new ArrayList<>();

    // Dodaje użytkownika do listy
    public void addUser(String user) {
        users.add(user);
    }

    // Zapisuje listę użytkowników do pliku
    public void saveUsersToFile() {
        try (FileWriter writer = new FileWriter("users.txt")) {
            for (String user : users) {
                writer.write(user + System.lineSeparator());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // Wysyła powiadomienie do wszystkich użytkowników
    public void sendNotification(String message) {
        for (String user : users) {
            System.out.println("Wysyłanie wiadomości do " + user + ": " + message);
        }
    }

    public static void main(String[] args) {
        UserManager manager = new UserManager();
        manager.addUser("Alice");
        manager.addUser("Bob");
        manager.saveUsersToFile();
        manager.sendNotification("Witajcie w naszej aplikacji!");
    }
}

W powyższym kodzie klasa UserManager ma trzy różne odpowiedzialności:

  1. Dodawanie użytkowników.
  2. Zapisywanie użytkowników do pliku.
  3. Wysyłanie powiadomień do użytkowników.

Poprawiony kod zgodny z zasadą SRP

Rozdzielmy odpowiedzialności na osobne klasy:

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

// Klasa odpowiedzialna za zarządzanie użytkownikami
public class UserManager {
    private List<String> users = new ArrayList<>();

    public void addUser(String user) {
        users.add(user);
    }

    public List<String> getUsers() {
        return users;
    }
}

// Klasa odpowiedzialna za zapisywanie użytkowników do pliku
public class UserFileSaver {
    public void saveUsersToFile(List<String> users, String filename) {
        try (FileWriter writer = new FileWriter(filename)) {
            for (String user : users) {
                writer.write(user + System.lineSeparator());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// Klasa odpowiedzialna za wysyłanie powiadomień do użytkowników
public class UserNotifier {
    public void sendNotification(List<String> users, String message) {
        for (String user : users) {
            System.out.println("Wysyłanie wiadomości do " + user + ": " + message);
        }
    }
}


public class Main {
    public static void main(String[] args) {
        UserManager userManager = new UserManager();
        userManager.addUser("Alice");
        userManager.addUser("Bob");

        UserFileSaver fileSaver = new UserFileSaver();
        fileSaver.saveUsersToFile(userManager.getUsers(), "users.txt");

        UserNotifier notifier = new UserNotifier();
        notifier.sendNotification(userManager.getUsers(), "Witajcie w naszej aplikacji!");
    }
}

Analiza poprawionego kodu

  1. TaskManager: Klasa ta jest odpowiedzialna tylko za zarządzanie zadaniami – dodawanie ich do listy i udostępnianie listy zadań innym klasom.
  2. ReportGenerator: Klasa ta zajmuje się tylko generowaniem raportu na podstawie listy zadań. Przyjmuje listę zadań i zwraca sformatowany raport.
  3. ReportSaver: Klasa ta odpowiada za zapisywanie raportu do pliku. Przyjmuje raport i nazwę pliku, do którego ma być zapisany.

Scroll to Top