J'aimais les classes utilitaires remplies de méthodes statiques. Ils ont fait une grande consolidation des méthodes d'assistance qui, autrement, auraient causé la redondance et l'enfer de la maintenance. Ils sont très faciles à utiliser, aucune instanciation, aucune élimination, juste fire'n'forget. Je suppose que c'était ma première tentative involontaire de créer une architecture orientée services - beaucoup de services sans état qui faisaient juste leur travail et rien d'autre. Au fur et à mesure que le système se développe, les dragons arrivent.
Polymorphisme
Disons que nous avons la méthode UtilityClass.SomeMethod qui bourdonne joyeusement. Soudain, nous devons modifier légèrement la fonctionnalité. La plupart des fonctionnalités sont les mêmes, mais nous devons tout de même modifier quelques parties. S'il ne s'agissait pas d'une méthode statique, nous pourrions créer une classe dérivée et modifier le contenu de la méthode si nécessaire. Comme c'est une méthode statique, nous ne pouvons pas. Bien sûr, si nous avons juste besoin d'ajouter des fonctionnalités avant ou après l'ancienne méthode, nous pouvons créer une nouvelle classe et appeler l'ancienne à l'intérieur - mais c'est juste dégoûtant.
Problèmes d'interface
Les méthodes statiques ne peuvent pas être définies via des interfaces pour des raisons logiques. Et comme nous ne pouvons pas remplacer les méthodes statiques, les classes statiques sont inutiles lorsque nous devons les passer par leur interface. Cela nous rend incapables d'utiliser des classes statiques dans le cadre d'un modèle de stratégie. Nous pourrions corriger certains problèmes en passant des délégués au lieu d'interfaces .
Test
Cela va de pair avec les problèmes d'interface mentionnés ci-dessus. Comme notre capacité à interchanger les implémentations est très limitée, nous aurons également du mal à remplacer le code de production par du code de test. Encore une fois, nous pouvons les conclure, mais cela nous obligera à modifier de grandes parties de notre code juste pour pouvoir accepter des wrappers au lieu des objets réels.
Favorise les blobs
Comme les méthodes statiques sont généralement utilisées comme méthodes utilitaires et que les méthodes utilitaires ont généralement des objectifs différents, nous nous retrouverons rapidement avec une grande classe remplie de fonctionnalités non cohérentes - idéalement, chaque classe devrait avoir un seul objectif dans le système . Je préfère de loin avoir cinq fois les classes tant que leurs objectifs sont bien définis.
Fluage des paramètres
Pour commencer, cette petite méthode statique mignonne et innocente pourrait prendre un seul paramètre. Au fur et à mesure que la fonctionnalité augmente, quelques nouveaux paramètres sont ajoutés. Bientôt, d'autres paramètres sont ajoutés qui sont facultatifs, donc nous créons des surcharges de la méthode (ou ajoutons simplement des valeurs par défaut, dans les langues qui les prennent en charge). Avant longtemps, nous avons une méthode qui prend 10 paramètres. Seuls les trois premiers sont vraiment obligatoires, les paramètres 4-7 sont facultatifs. Mais si le paramètre 6 est spécifié, 7-9 doivent également être remplis ... Si nous avions créé une classe dans le seul but de faire ce que cette méthode statique a fait, nous pourrions résoudre ce problème en prenant les paramètres requis dans le constructeur, et permettant à l'utilisateur de définir des valeurs facultatives via des propriétés ou des méthodes pour définir plusieurs valeurs interdépendantes en même temps. De plus, si une méthode atteint ce niveau de complexité,
Exiger des consommateurs qu'ils créent une instance de classes sans raison
L'un des arguments les plus courants est: pourquoi exiger que les consommateurs de notre classe créent une instance pour invoquer cette méthode unique, tout en n'ayant aucune utilité pour l'instance par la suite? La création d'une instance d'une classe est une opération très bon marché dans la plupart des langages, donc la vitesse n'est pas un problème. L'ajout d'une ligne de code supplémentaire au consommateur est un faible coût pour jeter les bases d'une solution beaucoup plus maintenable à l'avenir. Et enfin, si vous voulez éviter de créer des instances, créez simplement un wrapper singleton de votre classe qui permet une réutilisation facile - bien que cela impose que votre classe soit sans état. S'il n'est pas sans état, vous pouvez toujours créer des méthodes de wrapper statiques qui gèrent tout, tout en vous offrant tous les avantages à long terme. Finalement,
Seul un Sith traite des absolus.
Bien sûr, il y a des exceptions à mon aversion pour les méthodes statiques. Les véritables classes d'utilité qui ne présentent aucun risque de gonflement sont d'excellents cas pour les méthodes statiques - System.Convert par exemple. Si votre projet est unique et ne nécessite aucune maintenance future, l'architecture globale n'est vraiment pas très importante - statique ou non statique, peu importe - la vitesse de développement, cependant.
Normes, normes, normes!
L'utilisation de méthodes d'instance ne vous empêche pas d'utiliser également des méthodes statiques, et vice versa. Tant qu'il y a un raisonnement derrière la différenciation et c'est standardisé. Il n'y a rien de pire que d'examiner une couche métier tentaculaire avec différentes méthodes de mise en œuvre.