Pourquoi un générateur devrait-il être une classe interne plutôt que dans son propre fichier de classe?

24

De nombreux Builder Patternexemples font de la Builderclasse interne de l'objet qu'il construit.

Cela a un certain sens car il indique ce que les Builderbuilds. Cependant, dans un langage typé statiquement, nous savons ce que les Builderbuilds.

D'autre part , si la Builderest une classe interne, vous devez savoir quelle classe les Builderbuilds sans regarder de l'intérieur Builder.

En outre, avoir le générateur comme classe interne réduit le nombre d'importations car il peut être référencé par la classe externe - si cela vous intéresse.

Et puis il y a des exemples pratiques où le Builderest dans le même paquet, mais pas une classe interne, comme StringBuilder. Vous savez que le Builder devrait construire un Stringcar il est nommé ainsi.

Cela étant dit, la seule bonne raison à laquelle je peux penser pour créer une Builderclasse intérieure est que vous savez ce qu'est la classe Buildersans connaître son nom ou en vous appuyant sur les conventions de dénomination. Par exemple, si StringBuilderc'était une classe interne de, Stringj'aurais probablement su qu'elle existait plus tôt que moi (spéculative).

Y a-t-il d'autres raisons de faire de la Builderclasse intérieure une ou cela revient-il simplement à la préférence et au rituel?

Nathanial
la source

Réponses:

30

Je pense que la raison de cela est que la classe interne (le constructeur) puisse accéder aux membres privés de la classe qu'elle construit.

Depuis http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Les classes imbriquées non statiques (classes internes) ont accès aux autres membres de la classe englobante, même si elles sont déclarées privées.

...

Considérez deux classes de niveau supérieur, A et B, où B a besoin d'accéder aux membres de A qui seraient autrement déclarés privés. En cachant la classe B dans la classe A, les membres de A peuvent être déclarés privés et B peut y accéder.

...

Comme pour les méthodes et variables d'instance, une classe interne est associée à une instance de sa classe englobante et a un accès direct aux méthodes et aux champs de cet objet.

Voici du code pour essayer d'illustrer cela:

class Example {

    private int x;

    public int getX() { return this.x; }

    public static class Builder {

        public Example Create() {
            Example instance = new Example();
            instance.x = 5; // Builder can access Example's private member variable
            return instance;
        }
    }
}

En tant que classe statique, Builder n'a pas d'instance spécifique d'exemple à laquelle il est lié. Cependant, étant donné une instance de Example (ou une instance qu'il crée lui-même), Builder peut toujours accéder aux membres privés de cette instance.

Apprenti du Dr Wily
la source
Excellente réponse, cela a du sens! Cependant, les modèles de générateur ont généralement une classe interne statique et ne peuvent accéder qu'aux membres privés statiques de la classe externe. Si vous aviez un constructeur pour une classe instanciée, ce serait toutes sortes de bizarres.
Nathanial
1
@Nathanial pas du tout, les variables d'instance privées sont également accessibles: ideone.com/7DyjDR
amon
1
@nathanial: Oui, mais le constructeur ne manipule pas la classe; c'est manipuler un objet de la classe que le constructeur lui-même a instancié.
Robert Harvey
@amon, je vois ce que vous y avez fait. Merci pour l'explication!
Nathanial
Plus précisément, il donne au constructeur l'accès à un constructeur privé pour la classe en cours de construction, permettant à cette classe d'être immuable (tous les champs finaux) et uniquement instanciable via le constructeur.
Matthew McPeak
1

Il n'y a pas de «devrait» dans ce cas. Définir un générateur dans une autre classe ou le séparer est orthogonal au modèle de générateur. De nombreux exemples le font en raison de la commodité de présenter le code dans un fichier cohérent (également pour accéder aux membres privés, mais cela dépend également du contexte). N'hésitez pas à faire autrement

AZ01
la source
Je ne sais pas pourquoi cette réponse a été rejetée, pour toute autre raison que «parce que ce n'est pas ainsi que nous procédons en Java». Le modèle de générateur fournit une enveloppe autour d'un constructeur qui prend un tas de paramètres. Si le constructeur prend ces paramètres, il n'est pas nécessaire que l'objet Builder accède aux membres privés.
Greg Burghardt