wake-up-neo.net

Le classi di utilità sono malvagie?

Ho visto questo thread 

Se una classe "Utilità" è malvagia, dove inserisco il mio codice generico?

e pensato perché le classi di utilità sono malvagie? 

Diciamo che ho un modello di dominio che è dozzine di classi profonde. Devo essere in grado di istanze xml-ify. Faccio un metodo toXml sul genitore? Creo una classe helper MyDomainXmlUtility.toXml? Questo è un caso in cui le esigenze aziendali si estendono all'intero modello di dominio - appartiene davvero come un metodo di istanza? Che dire se ci sono un sacco di metodi ausiliari sulla funzionalità xml dell'applicazione?

77
hvgotcodes

Le classi di utilità non sono esattamente malvagie, ma possono violare i principi che compongono un buon design orientato agli oggetti. In una buona progettazione orientata agli oggetti, la maggior parte delle classi dovrebbe rappresentare una singola cosa e tutti i suoi attributi e operazioni. Se stai operando su una cosa, quel metodo dovrebbe probabilmente essere un membro di quella cosa.

Tuttavia, ci sono momenti in cui è possibile utilizzare le classi di utilità per raggruppare insieme un numero di metodi: un esempio è la classe Java.util.Collections che fornisce un numero di utilità che possono essere utilizzate su qualsiasi raccolta Java. Questi non sono specifici per un particolare tipo di Collection, ma implementano algoritmi che possono essere usati su qualsiasi Collection.

In realtà, ciò che devi fare è pensare al tuo design e determinare dove ha più senso mettere i metodi. Di solito, è come operazioni all'interno di una classe. Tuttavia, a volte, è davvero una classe di utilità. Quando si utilizza una classe di utilità, tuttavia, non solo inserire metodi casuali in essa, ma organizzare i metodi per scopo e funzionalità.

105
Thomas Owens

Penso che il consenso generale sia che le classi di utilità non sono malvagie per sé . Hai solo bisogno di usarli con giudizio:

  • Progettare i metodi di utilità statici per essere generali e riutilizzabili. Assicurati che siano apolidi; cioè senza variabili statiche.

  • Se disponi di molti metodi di utilità, suddividili in classi in modo tale che sia facile per gli sviluppatori trovarli.

  • Non utilizzare classi di utilità in cui i metodi statici o di istanza in una classe di dominio potrebbero essere una soluzione migliore. Ad esempio, si consideri se i metodi in una classe base astratta o in una classe helper instantiable sarebbero una soluzione migliore.

  • Per Java 8 in poi, i "metodi predefiniti" in un'interfaccia potrebbero essere un'opzione migliore rispetto alle classi di utilità.


L'altro modo di guardare questa domanda è osservare che nella domanda citata, "Se le classi di utilità sono" malvagie "" è un argomento di paglia. È come me che chiedo:

"Se i maiali possono volare, dovrei portare un ombrello?". 

Nella domanda di cui sopra, in realtà non sto dicendo che i maiali possono volare ... o che sono d'accordo con la proposizione che potrebbe volare. 

Tipici "xyz is evil" dichiarazioni sono dispositivi retorici che sono pensati per farti pensare ponendo un punto di vista estremo. Sono raramente (se mai) intesi come affermazioni di fatto letterale. 

47
Stephen C

Le classi di utilità sono problematiche perché non riescono a raggruppare le responsabilità con i dati che le supportano.

Sono comunque estremamente utili e li costruisco tutto il tempo come strutture permanenti o come trampolini di lancio durante un refactoring più completo.

Da un Clean Code le classi di utilità di prospettiva violano la Single Responsibility e il Open-Closed Principle. Hanno molti motivi per cambiare e non sono estensibili. Dovrebbero davvero esistere solo durante il refactoring come cruft intermedio.

12
Alain O'Dea

Suppongo che inizi a diventare malvagio quando 

1) Diventa troppo grande (li raggruppo in categorie significative in questo caso).
2) I metodi che non dovrebbero essere metodi statici sono presenti  

Ma fintanto che queste condizioni non sono soddisfatte, penso che siano molto utili.

7
Enno Shioji

Regola del pollice

Puoi guardare questo problema da due punti di vista:

  • I metodi *Util generali sono spesso un suggerimento di progettazione di codice errato o convenzione di denominazione lenta. 
  • È una soluzione di design legittima per funzionalità stateless riutilizzabili tra domini. Si noti che per quasi tutti i problemi comuni esistono soluzioni esistenti. 

Esempio 1. Uso corretto delle classi/moduli util. Esempio di libreria esterna

Supponiamo che tu stia scrivendo un'applicazione che gestisce i prestiti e le carte di credito. I dati di questi moduli sono esposti attraverso i servizi Web nel formato json. In teoria è possibile convertire manualmente gli oggetti in stringhe che saranno in json, ma ciò reinventerebbe la ruota. La soluzione corretta sarebbe quella di includere in entrambi i moduli la libreria esterna utilizzata per convertire gli oggetti Java nel formato desiderato. (nell'immagine di esempio ho mostrato gson )

 enter image description here


Esempio 2. Uso corretto delle classi/moduli util. Scrivere il proprio util senza scuse per gli altri membri del team

Come caso d'uso, supponiamo di dover eseguire alcuni calcoli in due moduli di applicazione, ma entrambi devono sapere quando ci sono giorni festivi in ​​Polonia. In teoria è possibile eseguire questi calcoli all'interno dei moduli, ma sarebbe meglio estrarre questa funzionalità in un modulo separato. 

Ecco piccoli dettagli, ma importanti. La classe/modulo che hai scritto non è chiamato HolidayUtil, ma PolishHolidayCalculator. Funzionalmente è una classe util, ma siamo riusciti ad evitare Word generici. 

 enter image description here

4
Marcin Szymczak

Non sono del tutto d'accordo sul fatto che le classi di utilità siano malvagie.

Mentre una classe di utilità può violare i principi OO in qualche modo, non sempre sono cattivi.

Ad esempio, immagina di volere una funzione che pulirà una stringa di tutte le sottostringhe che corrispondono al valore x.

stl c ++ (al momento) non supporta direttamente questo.

Potresti creare un'estensione polimorfa di std::string.

Ma il problema è, vuoi davvero OGNI stringa che usi nel tuo progetto per essere la tua classe di stringa estesa?

Ci sono volte in cui OO non ha davvero senso, e questo è uno di questi. Vogliamo che il nostro programma sia compatibile con altri programmi, quindi continueremo con std::string e creeremo una classe StringUtil_ (o qualcosa del genere).

Direi che è meglio se ti attacchi con un solo util per classe. Direi che è sciocco avere un utile per tutte le classi o molti programmi di utilità per una classe.

3
HumbleWebDev

Ripensando a questa domanda ora, direi che i metodi di estensione C # distruggono completamente la necessità di classi di utilità. Ma non tutte le lingue hanno un costrutto così geniale.

Hai anche JavaScript, dove puoi semplicemente aggiungere una nuova funzione direttamente all'oggetto esistente. 

Ma non sono sicuro che ci sia un modo elegante per risolvere questo problema in una lingua più vecchia come il C++ ...

Un buon codice OO è piuttosto difficile da scrivere ed è difficile da trovare poiché scrivere Good OO richiede molto più tempo/conoscenza che scrivere un codice funzionale decente.

E quando hai un budget limitato, il tuo capo non è sempre felice di vedere che hai trascorso l'intera giornata a scrivere un sacco di lezioni ...

3
HumbleWebDev

Le classi di utilità sono cattive perché significano che sei troppo pigro per pensare a un nome migliore per la classe :)

Detto questo, sono pigro. A volte hai solo bisogno di portare a termine il lavoro e la tua mente è vuota ... questo è il momento in cui le classi "Utility" iniziano a insinuarsi.

3
Larry Watanabe

È molto facile etichettare qualcosa di utile semplicemente perché il progettista non può pensare a un posto appropriato dove inserire il codice. Ci sono spesso poche vere "utilità".

Come regola generale, di solito tengo il codice nel pacchetto in cui viene usato per la prima volta, quindi riadattato solo in un posto più generico se trovo che in seguito è necessario in altre parti. L'unica eccezione è se ho già un pacchetto che esegue funzionalità simili/correlate e il codice si adatta meglio lì.

2
mdma

Le classi di utilità contenenti metodi stateless stateless possono essere utili. Questi sono spesso molto facili da testare l'unità.

2
seand

La maggior parte delle classi Util sono cattive perché:

  1. Ampliano la portata dei metodi. Rendono pubblico il codice che altrimenti sarebbe privato. Se il metodo util è richiesto da più chiamanti in classi separate ed è stabile (ovvero non necessita di aggiornamento) è meglio, a mio parere, copiare e incollare metodi helper privati ​​nella classe chiamante. Una volta esposta come API, rendi più difficile capire quale sia il punto di accesso pubblico a un componente jar (mantieni una struttura gerarchica chiamata con un genitore per metodo. È più facile separare mentalmente in componenti che è più difficile quando hai metodi chiamati da più metodi padre). 
  2. Risultano in codice morto. I metodi Util nel tempo diventano inutilizzati man mano che la tua app si evolve e finisci con il codice inutilizzato che inquina il tuo codice base. Se fosse rimasto privato, il compilatore ti direbbe che il metodo non è utilizzato e potresti semplicemente rimuoverlo (il codice migliore non è affatto un codice). Una volta reso tale metodo non privato, il tuo computer sarà impotente per aiutarti a rimuovere il codice inutilizzato. Può essere chiamato da un diverso file jar per tutti i computer.

Esistono alcune analogie con le librerie statiche e dinamiche.

1
Sridhar-Sarnobat

Con Java 8 è possibile utilizzare i metodi statici nelle interfacce ... risolto il problema.

1
Marc T

Le classi di utilità non sono sempre malvagie. Ma dovrebbero contenere solo i metodi che sono comuni a un'ampia gamma di funzionalità. Se esistono metodi utilizzabili solo in un numero limitato di classi, prendere in considerazione la creazione di una classe astratta come genitore comune e inserire i metodi al suo interno.

0
Sid J