Refactoring.
A controlled technique for improving the design of existing code. Browse by group, see the code smells these techniques treat, the test smells in your test suite, or the smells of AI-generated code.
Problème : une méthode ne dispose pas de suffisamment de données pour effectuer certaines actions. Solution : créez un nouveau paramètre afin de transmettre les données nécessaires.
Problème : Une méthode n’est pas utilisée par d’autres classes ou n’est utilisée qu’au sein de sa propre hiérarchie de classes. Solution : Rendez la méthode privée ou protégée.
Problème : vos méthodes contiennent un groupe de paramètres qui se répète. Solution : remplacez ces paramètres par un objet.
Problème : Plusieurs méthodes effectuent des actions similaires qui ne diffèrent que par leurs valeurs, nombres ou opérations internes. Solution : Combinez ces méthodes en utilisant un paramètre qui transmettra la valeur particulière nécessaire.
Problème : vous récupérez plusieurs valeurs d'un objet, puis vous les passez comme paramètres à une méthode. Solution : essayez plutôt de passer l'objet entier.
Problème : un paramètre n’est pas utilisé dans le corps d’une méthode. Solution : supprimez le paramètre inutilisé.
Problème : la valeur d'un champ ne doit être définie qu'au moment de sa création et ne doit jamais changer par la suite. Solution : supprimez donc les méthodes qui modifient la valeur du champ.
Problème : Le nom d’une méthode n’explique pas ce que fait la méthode. Solution : Renommez la méthode.
Problème : vous avez un constructeur complexe qui fait autre chose que simplement affecter les valeurs des paramètres aux champs de l'objet. Solution : créez une méthode de fabrique et utilisez-la pour remplacer les appels au constructeur.
Problème : une méthode renvoie une valeur spéciale qui indique une erreur ? Solution : levez plutôt une exception.
Problème : Vous levez une exception là où un simple test ferait l'affaire ? Solution : Remplacez l'exception par un test conditionnel.
Problème : Une méthode est divisée en parties, chacune étant exécutée en fonction de la valeur d'un paramètre. Solution : Extrayez les différentes parties de la méthode dans leurs propres méthodes et appelez-les à la place de la méthode d'origine.
Problème : appeler une méthode de requête et passer son résultat comme paramètre d'une autre méthode, alors que cette méthode pourrait appeler directement la requête. Solution : au lieu de passer la valeur via un paramètre, essayez de placer un appel de requête à l'intérieur du corps de la méthode.
Problème : avez-vous une méthode qui renvoie une valeur mais modifie aussi quelque chose à l'intérieur d'un objet ? Solution : scindez la méthode en deux méthodes distinctes. Comme on peut s'y attendre, l'une doit renvoyer la valeur et l'autre modifier l'objet.
Problème : vous avez une association bidirectionnelle entre des classes, mais l'une des classes n'utilise pas les fonctionnalités de l'autre. Solution : supprimez l'association inutilisée.
Problème : vous avez un objet référence trop petit et trop rarement modifié pour justifier la gestion de son cycle de vie. Solution : transformez-le en objet valeur.
Problème : Vous avez deux classes qui ont chacune besoin d'utiliser les fonctionnalités de l'autre, mais l'association entre elles n'est qu'unidirectionnelle. Solution : Ajoutez l'association manquante à la classe qui en a besoin.
Problème : vous avez de nombreuses instances identiques d'une même classe que vous devez remplacer par un seul objet. Solution : convertissez les objets identiques en un unique objet de référence.
Problème : des données métier sont-elles stockées dans des classes responsables de l’interface graphique ? Solution : il est alors judicieux de séparer les données dans des classes distinctes, en assurant la liaison et la synchronisation entre la classe métier et l’interface graphique.
Problème : Une classe contient un champ de type collection ainsi qu'un simple getter et un simple setter pour manipuler la collection. Solution : Rendez la valeur renvoyée par le getter en lecture seule et créez des méthodes pour ajouter/supprimer des éléments de la collection.
Problème : vous avez un champ public. Solution : rendez le champ privé et créez des méthodes d'accès pour celui-ci.
Problème : Vous avez un tableau qui contient différents types de données. Solution : Remplacez le tableau par un objet qui aura des champs distincts pour chaque élément.
Problème : une classe (ou un groupe de classes) contient un champ de données. Ce champ possède son propre comportement et ses propres données associées. Solution : créez une nouvelle classe, placez-y l'ancien champ et son comportement, et stockez l'objet de cette classe dans la classe d'origine.
Problème : votre code utilise un nombre qui a une certaine signification. Solution : remplacez ce nombre par une constante portant un nom lisible qui explique la signification du nombre.
Problème : vous avez des sous-classes qui ne diffèrent que par leurs méthodes (renvoyant des constantes). Solution : remplacez ces méthodes par des champs dans la classe parente et supprimez les sous-classes.
Problème : Une classe possède un champ qui contient un code de type. Les valeurs de ce type ne sont pas utilisées dans des conditions d'opérateur et n'affectent pas le comportement du programme. Solution : Créez une nouvelle classe et utilisez ses objets à la place des valeurs du code de type.
Problème : vous avez un type codé qui influe sur le comportement mais vous ne pouvez pas recourir à des sous-classes pour vous en débarrasser. Solution : remplacez le code de type par un objet d'état. S'il faut remplacer la valeur d'un champ contenant le code de type, un autre objet d'état est « branché » à la place.
Problème : Vous avez un type codé qui affecte directement le comportement du programme (les valeurs de ce champ déclenchent différents codes dans des conditions). Solution : Créez des sous-classes pour chaque valeur du type codé. Puis extrayez les comportements pertinents de la classe d'origine vers ces sous-classes. Remplacez le code de contrôle de flux par du polymorphisme.
Problème : vous accédez directement aux champs privés à l'intérieur d'une classe. Solution : créez un getter et un setter pour le champ, et utilisez-les exclusivement pour accéder au champ.
Problème : vous avez une hiérarchie de classes dans laquelle une sous-classe est pratiquement identique à sa superclasse. Solution : fusionnez la sous-classe et la superclasse.
Problème : plusieurs clients utilisent la même partie de l'interface d'une classe. Autre cas : une partie de l'interface est identique dans deux classes. Solution : déplacez cette portion identique dans sa propre interface.
Problème : une classe possède des fonctionnalités qui ne sont utilisées que dans certains cas. Solution : créez une sous-classe et utilisez-la dans ces cas.
Problème : Vous avez deux classes qui partagent des champs et des méthodes communs. Solution : Créez une superclasse commune pour elles et déplacez-y tous les champs et méthodes identiques.
Problème : Vos sous-classes implémentent des algorithmes qui contiennent des étapes similaires dans le même ordre. Solution : Déplacez la structure de l'algorithme et les étapes identiques vers une superclasse, et laissez l'implémentation des étapes différentes dans les sous-classes.
Problème : vos sous-classes ont des constructeurs dont le code est en grande partie identique. Solution : créez un constructeur dans la superclasse et déplacez-y le code commun aux sous-classes. Appelez le constructeur de la superclasse dans les constructeurs des sous-classes.
Problème : deux classes possèdent le même champ. Solution : supprimez le champ des sous-classes et déplacez-le vers la super-classe.
Problème : Vos sous-classes ont des méthodes qui effectuent un travail similaire. Solution : Rendez les méthodes identiques, puis déplacez-les vers la superclasse appropriée.
Problème : un champ n'est-il utilisé que dans quelques sous-classes ? Solution : déplacez le champ vers ces sous-classes.
Problème : Un comportement implémenté dans une superclasse n’est-il utilisé que par une seule (ou quelques) sous-classe(s) ? Solution : Déplacez ce comportement vers les sous-classes.
Problème : une classe contient de nombreuses méthodes simples qui délèguent à toutes les méthodes d’une autre classe. Solution : faites de la classe un héritier du délégué, ce qui rend les méthodes de délégation inutiles.
Problème : vous avez une sous-classe qui n'utilise qu'une partie des méthodes de sa superclasse (ou il est impossible d'hériter des données de la superclasse). Solution : créez un champ, placez-y un objet de la superclasse, déléguez les méthodes à cet objet et supprimez l'héritage.
Problème : vous avez plusieurs conditions qui mènent au même résultat ou à la même action. Solution : regroupez toutes ces conditions en une seule expression.
Problème : un code identique se retrouve dans toutes les branches d’une condition. Solution : déplacez le code en dehors de la condition.
Problème : Vous avez une condition complexe (if-then/else ou switch). Solution : Décomposez les parties compliquées de la condition en méthodes distinctes : la condition, le then et le else.
Problème : pour qu'une portion de code fonctionne correctement, certaines conditions ou valeurs doivent être vraies. Solution : remplacez ces hypothèses par des vérifications d'assertion explicites.
Problème : comme certaines méthodes renvoient null au lieu d’objets réels, votre code comporte de nombreuses vérifications de null. Solution : au lieu de null, renvoyez un objet Null qui présente le comportement par défaut.
Problème : vous avez une variable booléenne qui sert de drapeau de contrôle pour plusieurs expressions booléennes. Solution : au lieu de la variable, utilisez break, continue et return.
Problème : vous avez une instruction conditionnelle qui exécute diverses actions selon le type ou les propriétés d’un objet. Solution : créez des sous-classes correspondant aux branches de la conditionnelle. Dans chacune, créez une méthode commune et déplacez-y le code de la branche correspondante de la conditionnelle. Remplacez ensuite la conditionnelle par l’appel de la méthode appropriée. Le résultat est que la bonne implémentation sera obtenue par polymorphisme en fonction de la classe de l’objet.
Problème : Vous avez un groupe de conditions imbriquées et il est difficile de déterminer le flux normal d'exécution du code. Solution : Isolez toutes les vérifications spéciales et les cas limites dans des clauses distinctes et placez-les avant les vérifications principales. Idéalement, vous devriez obtenir une liste « plate » de conditions, les unes après les autres.
Problème : lorsqu’une seule classe fait le travail de deux, cela devient malcommode. Solution : créez plutôt une nouvelle classe et placez-y les champs et les méthodes responsables de la fonctionnalité concernée.
Problème : le client obtient l'objet B à partir d'un champ ou d'une méthode de l'objet A. Le client appelle ensuite une méthode de l'objet B. Solution : créez une nouvelle méthode dans la classe A qui délègue l'appel à l'objet B. Désormais, le client ne connaît plus la classe B et n'en dépend plus.
Problème : Une classe ne fait presque rien et n’est responsable de rien, et aucune responsabilité supplémentaire n’est prévue pour elle. Solution : Déplacez toutes les fonctionnalités de la classe vers une autre.
Problème : une classe utilitaire ne contient pas la méthode dont vous avez besoin et vous ne pouvez pas l'y ajouter. Solution : ajoutez la méthode à une classe cliente et passez-lui un objet de la classe utilitaire en argument.
Problème : une classe utilitaire ne contient pas certaines méthodes dont vous avez besoin. Mais vous ne pouvez pas ajouter ces méthodes à la classe. Solution : créez une nouvelle classe contenant ces méthodes et faites-en soit une classe fille, soit un wrapper de la classe utilitaire.
Problème : un champ est davantage utilisé dans une autre classe que dans sa propre classe. Solution : créez un champ dans une nouvelle classe et redirigez vers lui tous les utilisateurs de l’ancien champ.
Problème : une méthode est davantage utilisée dans une autre classe que dans la sienne. Solution : créez une nouvelle méthode dans la classe qui utilise le plus la méthode, puis déplacez-y le code de l'ancienne méthode. Transformez le code de la méthode d'origine en une référence à la nouvelle méthode dans l'autre classe, ou bien supprimez-la entièrement.
Problème : Une classe possède trop de méthodes qui se contentent de déléguer à d’autres objets. Solution : Supprimez ces méthodes et obligez le client à appeler directement les méthodes finales.
Problème : vous avez un fragment de code qui peut être regroupé. Solution : déplacez ce code dans une nouvelle méthode (ou fonction) distincte et remplacez l'ancien code par un appel à la méthode.
Problème : vous avez une expression difficile à comprendre. Solution : placez le résultat de l'expression ou de ses parties dans des variables distinctes qui se passent d'explication.
Problème : lorsque le corps d'une méthode est plus parlant que la méthode elle-même, employez cette technique. Solution : remplacez les appels à la méthode par son contenu, puis supprimez la méthode.
Problème : Vous avez une variable temporaire à laquelle est affecté le résultat d’une simple expression, et rien de plus. Solution : Remplacez les références à cette variable par l’expression elle-même.
Problème : une valeur est affectée à un paramètre à l'intérieur du corps d'une méthode. Solution : utilisez une variable locale au lieu d'un paramètre.
Problème : Vous avez une longue méthode dans laquelle les variables locales sont si entremêlées que vous ne pouvez pas appliquer Extraire une méthode. Solution : Transformez la méthode en une classe distincte afin que les variables locales deviennent des champs de la classe. Vous pourrez alors scinder la méthode en plusieurs méthodes au sein de la même classe.
Problème : vous placez le résultat d'une expression dans une variable locale pour l'utiliser plus tard dans votre code. Solution : déplacez l'expression entière dans une méthode distincte et renvoyez-en le résultat. Interrogez la méthode au lieu d'utiliser une variable. Intégrez la nouvelle méthode dans d'autres méthodes si nécessaire.
Problème : vous avez une variable locale utilisée pour stocker différentes valeurs intermédiaires à l'intérieur d'une méthode (à l'exception des variables de boucle). Solution : utilisez des variables différentes pour des valeurs différentes. Chaque variable ne doit être responsable que d'une seule chose en particulier.
Problème : vous souhaitez remplacer un algorithme existant par un nouveau ? Solution : remplacez le corps de la méthode qui implémente l’algorithme par un nouvel algorithme.