Historia pytania
Od początku Java była rozwijana jako język obiektowy, w którym głównym zadaniem było tworzenie instancji klas. Jednak dla często używanych metod (np. sortowania, przekształcania danych) zaczęły pojawiać się klasy narzędziowe ze zbiorem metod statycznych (np. java.util.Collections).
Problem
Metody statyczne ułatwiają wywoływanie funkcji pomocniczych, ale nie nadają się do przechowywania stanu, wstrzykiwania zależności i testowania w izolacji. Z drugiej strony, instancje klas są bardziej elastyczne, ale zwiększają ilość kodu na inicjalizację i wymagają przemyślanego cyklu życia.
Rozwiązanie
Klasy narzędziowe (utility classes) — zestaw statycznych metod bez stanu, nie wymagają tworzenia obiektu. Dobre do manipulacji kolekcjami, przekształceń, operacji matematycznych.
Instancje klas — przechowują stan, korzystają z zależności, zapewniają rozbudowę i testowalność. Stosowane w logice biznesowej, serwisach, kontrolerach itp.
Przykład kodu:
// Przykład klasy narzędziowej public class MathUtils { public static int add(int a, int b) { return a + b; } } // Użycie: int sum = MathUtils.add(1, 2); // Przykład instancji klasy dla logiki biznesowej public class OrderService { private final OrderRepository repo; public OrderService(OrderRepository repo) { this.repo = repo; } public void placeOrder(Order o) { repo.save(o); } }
Kluczowe cechy:
Czy można dziedziczyć klasy narzędziowe i rozszerzać ich metody statyczne?
Nie, zazwyczaj klasy narzędziowe są deklarowane jako finalne, z prywatnym konstruktorem. Dziedziczenie metod statycznych jest dostępne, ale nie ma sensu, ponieważ metody statyczne nie są dziedziczone na poziomie wywołania instancji.
Przykład kodu:
public final class MyUtils { private MyUtils() {} // zapobiega tworzeniu instancji }
Czy klasy narzędziowe mogą zawierać stan?
Nie. Jeśli klasa narzędziowa zawiera stan (pola instancyjne lub statyczne), narusza to zasadę tworzenia narzędzi, prowadzi do błędów wielowątkowych i pogarsza czytelność.
Czy można mockować metody statyczne klas narzędziowych podczas testowania?
Tylko za pomocą specjalnych narzędzi typu PowerMock, które sprawiają, że testy są bardziej skomplikowane i czasami niestabilne. W normalnych przypadkach podejście przyjazne DI z instancją jest preferowane do testów.
W projekcie wszystkie serwisy są realizowane przy pomocy metod statycznych. Wstrzykiwanie zależności jest niemożliwe, testy jednostkowe nie są izolowane, każdy test zależy od stanu środowiska.
Plusy:
Minusy:
W serwisach stosuje się oddzielne klasy z wstrzykiwaniem zależności, przez interfejsy. Do przekształceń i prostych operacji wykorzystuje się oddzielne klasy narzędziowe bez stanu.
Plusy:
Minusy: