web-dev-qa-db-fra.com

Les classes utilitaires sont diaboliques?

J'ai vu ce fil 

Si une classe "Utilitaires" est diabolique, où dois-je placer mon code générique?

et pensé pourquoi les classes utilitaires sont-elles diaboliques? 

Disons que j'ai un modèle de domaine qui a des dizaines de classes de profondeur. Je dois être capable d'instances xml-ify. Est-ce que je crée une méthode toXml sur le parent? Est-ce que je crée une classe d'assistance MyDomainXmlUtility.toXml? Il s’agit d’un cas où le besoin commercial s’applique à l’ensemble du modèle de domaine: est-ce vraiment une méthode d’instance? Qu'en est-il s'il y a un tas de méthodes auxiliaires sur la fonctionnalité XML de l'application?

77
hvgotcodes

Les classes utilitaires ne sont pas vraiment diaboliques, mais elles peuvent violer les principes qui composent un bon design orienté objet. Dans une bonne conception orientée objet, la plupart des classes devraient représenter une seule chose, ainsi que tous ses attributs et opérations. Si vous opérez sur une chose, cette méthode devrait probablement être un membre de cette chose.

Cependant, vous pouvez parfois utiliser des classes d'utilitaires pour regrouper un certain nombre de méthodes, par exemple la classe Java.util.Collections qui fournit un certain nombre d'utilitaires pouvant être utilisés sur n'importe quelle collection Java. Celles-ci ne sont pas spécifiques à un type particulier de Collection, mais implémentent des algorithmes pouvant être utilisés sur n'importe quelle Collection.

En réalité, vous devez réfléchir à votre conception et déterminer où il est le plus logique de définir les méthodes. Habituellement, c'est comme des opérations à l'intérieur d'une classe. Cependant, parfois, il s’agit bien d’une classe d’utilité. Toutefois, lorsque vous utilisez une classe d’utilitaires, ne vous contentez pas d’y insérer des méthodes aléatoires, mais organisez-les plutôt par fonction et par fonctionnalité.

105
Thomas Owens

Je pense que le consensus général est que les classes d’utilité ne sont pas mauvaises en soi . Il vous suffit de les utiliser judicieusement:

  • Concevez les méthodes d’utilité statique pour qu’elles soient générales et réutilisables. Assurez-vous qu'ils sont apatrides; c'est-à-dire pas de variables statiques.

  • Si vous avez beaucoup de méthodes utilitaires, partitionnez-les en classes de manière à faciliter leur recherche par les développeurs.

  • N'utilisez pas de classes utilitaires où des méthodes statiques ou d'instance dans une classe de domaine constitueraient une meilleure solution. Par exemple, demandez-vous si les méthodes d'une classe de base abstraite ou d'une classe d'assistance instanciable constituent une meilleure solution.

  • À partir de Java 8, les "méthodes par défaut" dans une interface peuvent constituer une meilleure option que les classes d’utilitaires.


L’autre façon de regarder cette question est de constater que, dans la question citée, "Si les classes d’utilité sont" pervers "" est un argument de paille. C'est comme si je demandais:

"Si les cochons peuvent voler, dois-je porter un parapluie?". 

Dans la question ci-dessus, je ne dis pas réellement que les porcs peuvent voler ... ou que je suis d'accord avec la proposition qu'ils pourraient voler. 

Les énoncés typiques "xyz est diabolique" sont des instruments rhétoriques destinés à vous faire réfléchir en vous présentant un point de vue extrême. Ils sont rarement (voire jamais) conçus comme des déclarations de faits littéraux. 

47
Stephen C

Les classes d'utilitaires posent problème car elles ne permettent pas de regrouper les responsabilités avec les données qui les prennent en charge.

Ils sont toutefois extrêmement utiles et je les construis tout le temps soit comme structures permanentes, soit comme tremplins lors d’un remaniement plus approfondi.

D'un Clean Code les classes d'utilitaires de perspective violent le principe de responsabilité unique et le principe d'ouverture-fermeture. Ils ont de nombreuses raisons de changer et ne sont par nature pas extensibles. Ils ne devraient vraiment exister que lors de la refactorisation en tant que cruft intermédiaire.

12
Alain O'Dea

Je suppose que ça commence à devenir diabolique quand 

1) Cela devient trop gros (groupez-les simplement dans des catégories significatives dans ce cas).
2) Il existe des méthodes qui ne devraient pas être statiques  

Mais tant que ces conditions ne sont pas remplies, je pense qu'elles sont très utiles.

7
Enno Shioji

Règle de base

Vous pouvez examiner ce problème sous deux angles:

  • Les méthodes globales *Util sont souvent une suggestion de mauvaise conception de code ou de convention de nommage paresseuse. 
  • C'est une solution de conception légitime pour des fonctionnalités sans état réutilisables entre domaines. Veuillez noter que pour presque tous les problèmes courants, il existe des solutions existantes. 

Exemple 1. Utilisation correcte de util classes/modules. Exemple de bibliothèque externe

Supposons que vous écrivez une application qui gère les prêts et les cartes de crédit. Les données de ces modules sont exposées via des services Web au format json. En théorie, vous pouvez convertir manuellement des objets en chaînes qui seront en json, mais cela réinventerait la roue. La solution correcte consisterait à inclure dans les deux modules une bibliothèque externe utilisée pour convertir les objets Java au format souhaité. (dans l'exemple d'image que j'ai montré gson )

 enter image description here


Exemple 2. Utilisation correcte de util classes/modules. Écrivez votre propre util sans excuses aux autres membres de l'équipe

En tant que cas d'utilisation, supposons qu'il soit nécessaire d'effectuer des calculs dans deux modules d'application, mais que les deux aient besoin de savoir quand il y a des jours fériés en Pologne. En théorie, vous pouvez effectuer ces calculs à l'intérieur de modules, mais il serait préférable d'extraire cette fonctionnalité pour séparer les modules. 

Voici un détail petit mais important. La classe/le module que vous avez écrit ne s'appelle pas HolidayUtil, mais PolishHolidayCalculator. Sur le plan fonctionnel, il s'agit d'une classe util, mais nous avons réussi à éviter les mots génériques. 

 enter image description here

4
Marcin Szymczak

Je ne suis pas tout à fait d'accord pour dire que les classes utilitaires sont diaboliques.

Bien qu'une classe d'utilitaires puisse violer les principes OO à certains égards, elles ne sont pas toujours mauvaises.

Par exemple, imaginons que vous souhaitiez une fonction qui nettoie une chaîne de toutes les sous-chaînes correspondant à la valeur x.

stl c ++ (à partir de maintenant) ne supporte pas directement cela.

Vous pouvez créer une extension polymorphe de std::string.

Mais le problème est, voulez-vous vraiment que CHAQUE CHAQUE chaîne que vous utilisez dans votre projet soit votre classe de chaîne étendue?

Il y a des moments où OO n'a pas vraiment de sens, et c'est l'un d'entre eux. Nous voulons que notre programme soit compatible avec d'autres programmes, nous allons donc rester avec std::string et créer une classe StringUtil_ (ou quelque chose).

Je dirais que c'est mieux si vous vous en tenez à un utilitaire par classe. Je dirais que c'est idiot d'avoir un utilitaire pour toutes les classes ou plusieurs utils pour une classe.

3
HumbleWebDev

En repensant à cette question, je dirais que les méthodes d’extension C # détruisent complètement le besoin de classes d’utilitaires. Mais toutes les langues n’ont pas une construction aussi géniale.

Vous avez également JavaScript, où vous pouvez simplement ajouter une nouvelle fonction à l'objet existant. 

Mais je ne suis pas sûr qu'il existe vraiment un moyen élégant de résoudre ce problème dans un langage plus ancien comme le C++ ...

Un bon code OO est un peu difficile à écrire et est difficile à trouver car écrire Bon OO nécessite beaucoup plus de temps/de connaissances que d'écrire un code fonctionnel correct.

Et quand vous avez un budget serré, votre patron n'est pas toujours content de voir que vous avez passé toute la journée à écrire un tas de cours ...

3
HumbleWebDev

Les classes utilitaires sont mauvaises car elles signifient que vous êtes trop fainéant pour imaginer un meilleur nom pour la classe :)

Cela étant dit, je suis paresseux. Parfois, vous avez juste besoin de faire le travail et votre esprit est vide. C'est à ce moment-là que les cours "Utilitaires" commencent à s’insérer.

3
Larry Watanabe

Il est très facile de définir un utilitaire simplement parce que le concepteur ne pouvait pas trouver un endroit approprié pour insérer le code. Il y a souvent peu de véritables "utilitaires".

En règle générale, je conserve le code dans le paquet où il a été utilisé pour la première fois, puis ne refactifie que vers un emplacement plus générique si je découvre que plus tard, il sera vraiment nécessaire ailleurs. La seule exception est si j'ai déjà un paquet qui exécute des fonctionnalités similaires/liées, et le code y correspond le mieux.

2
mdma

Les classes d'utilitaires contenant des méthodes statiques stateless peuvent être utiles. Celles-ci sont souvent très faciles à tester.

2
seand

La plupart des classes Util sont mauvaises parce que:

  1. Ils élargissent le champ des méthodes. Ils rendent public un code qui serait autrement privé. Si la méthode util est requise par plusieurs appelants dans des classes distinctes et est stable (c’est-à-dire qu’elle n’a pas besoin d’être mise à jour), il est préférable, à mon avis, de copier et coller des méthodes d’aide privée dans la classe d’appel. Une fois que vous l'exposez en tant qu'API, il est plus difficile de comprendre ce qu'est le point d'entrée public d'un composant jar (vous conservez une arborescence appelée structure, avec un parent par méthode. Il est plus facile de séparer mentalement les composants, ce qui est plus difficile lorsque vous avez des méthodes appelées à partir de plusieurs méthodes parentes). 
  2. Ils résultent en un code mort. Au fil du temps, les méthodes Util deviennent inutilisées à mesure que votre application évolue et vous vous retrouvez avec un code inutilisé polluant votre base de code. Si elle était restée privée, votre compilateur vous dirait que la méthode est inutilisée et vous pouvez simplement la supprimer (le meilleur code est aucun code). Une fois cette méthode rendue privée, votre ordinateur sera impuissant à supprimer le code inutilisé. Il peut être appelé depuis un fichier JAR différent pour tout ce que l’ordinateur sait.

Il existe certaines analogies entre les bibliothèques statiques et dynamiques.

1
Sridhar-Sarnobat

Avec Java 8, vous pouvez utiliser des méthodes statiques dans les interfaces ... problème résolu.

1
Marc T

Les classes utilitaires ne sont pas toujours pervers. Mais elles ne doivent contenir que les méthodes communes à une large gamme de fonctionnalités. S'il existe des méthodes qui ne sont utilisables que par un nombre limité de classes, envisagez de créer une classe abstraite en tant que parent commun et mettez-y les méthodes.

0
Sid J