Storia della questione
Fin dall'inizio, Java è stato sviluppato come un linguaggio orientato agli oggetti, dove il compito principale era risolvere problemi creando istanze di classi. Tuttavia, per i metodi frequentemente utilizzati (come ordinamento, trasformazione dei dati), sono emerse classi utility con un insieme di metodi statici (ad esempio, java.util.Collections).
Problema
I metodi statici semplificano la chiamata di funzioni di utilità, ma non sono adatti per memorizzare stato, iniettare dipendenze e testare in isolamento. D'altra parte, le istanze di classi sono più flessibili, ma aumentano la quantità di codice per l'inizializzazione e richiedono un ciclo di vita ben progettato.
Soluzione
Classi utility (utility classes) — un insieme di metodi statici senza stato, non richiedono la creazione di un oggetto. Sono buone per manipolare collezioni, trasformazioni, operazioni matematiche.
Istanze di classi — memorizzano stato, usano dipendenze, garantiscono estensibilità e testabilità. Sono applicate nella logica di business, servizi, controller, ecc.
Esempio di codice:
// Esempio di classe utility public class MathUtils { public static int add(int a, int b) { return a + b; } } // Utilizzo: int sum = MathUtils.add(1, 2); // Esempio di istanza di classe per la logica di business public class OrderService { private final OrderRepository repo; public OrderService(OrderRepository repo) { this.repo = repo; } public void placeOrder(Order o) { repo.save(o); } }
Caratteristiche chiave:
È possibile ereditare classi utility e estendere i loro metodi statici?
No, di solito le classi utility vengono dichiarate final, con costruttore privato. L'ereditarietà dei metodi statici è disponibile, ma non ha senso, poiché i metodi statici non vengono ereditati a livello di chiamata dell'istanza.
Esempio di codice:
public final class MyUtils { private MyUtils() {} // impedisce la creazione di un'istanza }
Le classi utility possono contenere stato?
No. Se una classe utility contiene stato (campi instance o static), viola il principio di scrittura delle utility, porta a errori di multithreading e riduce la leggibilità.
È possibile eseguire il mocking dei metodi statici delle classi utility durante i test?
Solo con strumenti speciali come PowerMock, che rendono i test più complessi e talvolta instabili. In condizioni normali, un approccio amico della DI con un'istanza è preferibile per i test.
Nel progetto, tutti i servizi sono implementati utilizzando metodi statici utility. L'iniezione delle dipendenze è impossibile, i test unitari non sono isolati, ogni test dipende dallo stato dell'ambiente.
Pro:
Contro:
Nei servizi vengono utilizzate singole classi con iniezione delle dipendenze, tramite interfacce. Per trasformazioni e operazioni semplici si utilizzano classi utility separate senza stato.
Pro:
Contro: