Anonyme vs classes internes nommées? – les meilleures pratiques?

J’ai une classe, appelons-le LineGraph, qui rend un graphique linéaire. Je dois le sous-classer, mais la classe dérivée n’est utilisée qu’à un seul endroit et est couplée à la classe qui l’utilise. Donc, j’utilise une classe interne.

Je vois deux façons de le faire:

Classe interne anonyme

public class Gui { LineGraph graph = new LineGraph() { // extra functionality here. }; } 

Classe interne nommée

 public class Gui { MyLineGraph graph = new MyLineGraph(); private class MyLineGraph extends LineGraph { // extra functionality here. } } 

Je ne suis pas fan des classes internes anonymes, car franchement je pense que ça a l’air vraiment moche. Mais dans le cas d’une sous-classe qui n’est utilisée qu’à un seul endroit, une classe interne nommée est-elle exagérée? Quelle est la pratique acceptée?

L’un des avantages des classes internes anonymes est que personne ne peut jamais l’utiliser ailleurs, alors qu’une classe interne nommée peut être utilisée (ne serait-ce que par la classe qui l’a créée si elle est rendue privée). C’est une petite distinction, mais cela signifie que vous pouvez protéger une classe interne contre une utilisation accidentelle ailleurs.

En outre, l’utilisation de la classe interne anonyme permet à quiconque lit votre code de prendre la tête – “cette classe n’est utilisée qu’ici et nulle part ailleurs”. Si vous voyez une classe interne nommée, quelqu’un pourrait penser qu’elle serait utilisée à plusieurs endroits de la classe.

Ils sont très similaires, donc aucun point ne change la donne. Je pense juste que cela aide pour la clarté si vous utilisez des classes internes anonymes pour des one-off et des classes internes nommées quand elles sont utilisées plusieurs fois dans la classe.

(Contrepoint à Daniel Lew)

Un inconvénient des classes internes anonymes est que personne ne peut jamais l’utiliser ailleurs, alors qu’une classe interne nommée peut être utilisée (ne serait-ce que par la classe qui l’a créée si elle est rendue privée). C’est une petite distinction, mais cela signifie que vous pouvez vous assurer qu’une classe interne n’est pas recréée accidentellement ailleurs.

En outre, l’utilisation de la classe interne anonyme donne plus de difficulté à ceux qui lisent votre code car ils doivent ensuite parsingr cette classe qui est sortie de nulle part. En utilisant une classe interne nommée, vous pouvez organiser davantage la source.

J’ai vu des cas où il y a deux (ou plus) classes internes anonymes avec exactement le même code. Dans les interfaces graphiques en particulier (où vous pouvez avoir plusieurs contrôles exécutant la même action), cela peut se produire (et je parle du code de production, pas du code que mes élèves ont écrit).

Le problème de la lisibilité va dans les deux sens, certaines personnes trouvent que les classes internes anonymes sont meilleures car elles vous permettent de voir ce qui se passe en une fois, d’autres trouvent cela distrayant. Cette partie se résume à des préférences personnelles.

De plus, rendre une classe statique est plus efficace, si vous déclarez une classe interne anonyme dans une instance, il y aura plus de surcharge, ce qui, si vous n’avez pas besoin d’accéder aux variables d’instance, est inutile jusqu’à ce qu’il se présente comme un problème).

Ma préférence personnelle est d’utiliser des classes non anonymes car elles permettent une plus grande flexibilité lorsque le code est modifié ultérieurement.

Pourquoi avez-vous besoin de le sous-classer? Si c’est juste pour remplacer une méthode virtuelle existante, je pense qu’une classe interne anonyme est acceptable. Si vous ajoutez des fonctionnalités supplémentaires, j’utiliserais une classe nommée. J’en ferais une classe nestede (c’est-à-dire avec le modificateur static ) – je les trouve plus faciles à raisonner 🙂

Faites la chose la plus simple possible : utilisez la classe interne anonyme.

Si vous trouvez plus tard que vous avez besoin d’une scope plus large, refactorisez le code pour prendre en charge cela.

(Vous feriez la même chose avec les variables – en les plaçant dans la scope la plus spécifique. Il est logique de faire la même chose avec d’autres ressources source.)

Les classes internes anonymes sont difficiles à déboguer dans Eclipse (c’est ce que j’utilise). Vous ne pourrez pas regarder les valeurs de variables / injecter des valeurs simplement en cliquant avec le bouton droit de la souris.

Un inconvénient des classes internes est qu’elles ne peuvent pas être statiques. Cela signifie que contiendra une référence à la classe externe qui les contient.

Les classes internes non statiques peuvent poser problème. Par exemple, une classe interne a été sérialisée récemment, mais la classe externe n’était pas sérialisable. La référence cachée signifiait que la classe externe serait également sérialisée, ce qui a bien sûr échoué, mais il a fallu du temps pour savoir pourquoi.

Là où je travaille, nos meilleures pratiques de codage encouragent les classes internes statiques (dans la mesure du possible) car elles transportent moins de bagages cachés et sont plus minces.

Ma règle de base personnelle: si la classe interne anonyme doit être petite, respectez une classe anonyme. Small étant défini comme étant environ 20 à 30 lignes ou moins. Si ça va durer plus longtemps, cela commence à être illisible à mon avis, donc je fais une classe interne nommée. Je me souviens avoir vu une classe interne anonyme de plus de 4000 lignes.

Les classes internes anonymes seraient généralement la voie à suivre. Je les trouve très lisibles. Cependant, si l’instance de cette classe a besoin d’être sérialisée (même si ce n’est que parce que c’est un champ de quelque chose d’autre), je vous recommande fortement d’utiliser des classes internes nommées. Les noms des classes internes anonymes dans le bytecode peuvent changer très facilement, ce qui peut casser la sérialisation.

Les classes anonymes ne peuvent pas avoir de constructeur, car elles n’ont pas de nom. Si vous devez passer d’autres variables que celles du ou des constructeurs de la classe que vous étendez, vous devez utiliser une classe interne nommée (statique). Cela peut parfois être surmonté en utilisant des variables finales dans la méthode / le code qui les entoure, mais c’est un peu moche (et peut conduire à ce que Robin a dit).

Je n’ai pas de problème avec les classes anonymes simples. Mais si elle comporte plus de quelques lignes de code ou quelques méthodes, une classe interne est plus claire. Je pense aussi que dans certaines conditions, ils ne devraient jamais être utilisés. Comme quand ils doivent renvoyer des données.

J’ai vu du code où un tableau final de 1 élément est utilisé pour renvoyer des données d’un appel à une classe interne anonyme. Dans la méthode de la classe anon, l’élément unique est défini, puis ce «résultat» extrait une fois la méthode terminée. Code valide mais laid.

Cours anonymes:

  • ne peut rien avoir de static dans la définition (classe statique, champ statique, initialiseur statique, etc.)
  • les champs ne peuvent pas être inspectés dans Eclipse
  • ne peut pas être utilisé comme un type ( Foo$1 myFoo=new Foo$1(){int x=0;} ne fonctionne pas)
  • ne peut pas être trouvé en utilisant le nom de la classe dans Eclipse (la recherche de Foo$1 ne fonctionne pas pour moi)
  • ne peut pas être réutilisé

Les classes anonymes peuvent cependant avoir un initialiseur comme {super.foo(finalVariable+this.bar);}

Les classes internes nommées n’ont pas ces limitations, mais même si l’une est utilisée exclusivement au milieu d’une longue procédure, la déclaration devra être déplacée jusqu’à la classe nommée suivante.

Je préfère personnellement les classes internes anonymes si les ressortingctions ne s’appliquent pas car:

  • Je sais que tous les champs supplémentaires ne sont référencés que dans la définition de la classe.
  • Eclipse peut les convertir facilement en classes nestedes.
  • Je n’ai pas besoin de copier les variables que je veux utiliser. Je peux juste les déclarer finales et les référencer. Ceci est particulièrement utile lorsque j’ai beaucoup de parameters.
  • Le code qui interagit est rapproché.

Je pense que ce que vous avez fait est tout à fait logique dans ce cas et que vous le regardiez d’une manière ou d’une autre, je pense que vous divisez vraiment les choses en deux. Ils sont tous les deux si similaires et l’un ou l’autre fonctionnera.

Je pense que c’est une question de goût. Je préfère utiliser des classes anonymes pour les foncteurs . Mais dans votre cas, j’utiliserais une classe interne, car je pense que vous allez y mettre plus de quelques lignes de code, peut-être plus qu’une méthode. Et cela mettrait l’accent sur le fait qu’il ajoute des fonctionnalités à la superclasse, en le plaçant dans la classe, plutôt que de le cacher quelque part dans une méthode. De plus, qui sait, peut-être qu’un jour, vous aurez peut-être besoin de la sous-classe ailleurs. Cela dépend bien sûr de votre connaissance de l’évolution de votre logiciel. À part ça, retournez simplement une pièce. 🙂

Je viens de discuter avec mon collègue et je cherchais à obtenir l’opinion populaire.

Je suis d’accord avec TofuBeer. Si votre code comporte plus de 2 lignes, ce n’est probablement pas une solution unique et peut être réutilisé un jour. Si vous créez un formulaire en utilisant un modèle MVC, vous pouvez avoir 20 éléments contrôlables sur une page au lieu d’encombrer la vue avec des tonnes de classes anonymouse (votre vue a probablement été créée à l’aide d’un générateur GUI et le code a été créé automatiquement). éditer la source même pas une option) vous allez probablement alimenter chaque élément à un contrôleur. Vous pouvez imbriquer des classes internes dans le contrôleur pour gérer chaque interface de gestionnaire / écouteur différente requirejse par votre vue. Cela organise le code vraiment bien, en particulier si vous avez une convention selon laquelle votre classe de gestionnaire doit être nommée en utilisant le nom de l’élément graphique (comme backButtonHandler pour un backButtonElement). Cela a très bien fonctionné pour nous et nous avons écrit un outil d’enregistrement automatique (lorsque vous enregistrez un contrôleur sur une vue, la vue recherche les classes internes en utilisant le nom de l’élément et les utilise pour un gestionnaire sur chaque élément nommé). Cela ne serait pas possible avec des classes anonymes et rendrait le contrôleur beaucoup plus recyclable.

TLDR: en cas de doute, écrivez une classe interne nommée. Vous ne saurez jamais si quelqu’un veut réutiliser votre code un jour (sauf s’il s’agit de deux lignes, alors vous devez vous demander si ce code sent?). Le code bien organisé présente des avantages beaucoup plus importants à long terme, en particulier lorsque votre projet est en maintenance.

Avec les classes internes anonymes, nous ne pouvons pas changer l’état des membres de classe inclus. Ils doivent être déclarés comme définitifs.