Un constructeur peut-il être privé ? En quoi un constructeur privé est-il utile ?
Du point de vue de la testabilité - ils représentent un état global, qui est difficile à prévoir (et à tester)
Un constructeur peut-il être privé ? En quoi un constructeur privé est-il utile ?
Oui, un constructeur peut être privé. Il y a différentes utilisations de ceci. L'une de ces utilisations est le singleton anti-modèle de conception que je vous déconseille d'utiliser. Une autre utilisation, plus légitime, est la délégation des constructeurs ; vous pouvez avoir un constructeur qui prend beaucoup d'options différentes qui est vraiment un détail d'implémentation, donc vous le rendez privé, mais ensuite vos autres constructeurs lui sont délégués.
À titre d'exemple de délégation des constructeurs, la classe suivante vous permet d'enregistrer une valeur et un type, mais elle ne vous permet de le faire que pour un sous-ensemble de types. Il est donc nécessaire de rendre le constructeur général privé pour garantir que seuls les types autorisés sont utilisés. Le constructeur privé commun aide à la réutilisation du code.
public class MyClass {
private final String value;
private final String type;
public MyClass(int x){
this(Integer.toString(x), "int");
}
public MyClass(boolean x){
this(Boolean.toString(x), "boolean");
}
public String toString(){
return value;
}
public String getType(){
return type;
}
private MyClass(String value, String type){
this.value = value;
this.type = type;
}
}
Modifier
En regardant cette réponse de plusieurs années plus tard, je voudrais noter que cette réponse est à la fois incomplète et aussi un peu extrême. Les singletons sont en effet un anti-modèle et doivent généralement être évités dans la mesure du possible ; cependant, il existe de nombreuses utilisations des constructeurs privés en dehors des singletons, et ma réponse n'en cite qu'une.
Pour donner quelques autres cas où les constructeurs privés sont utilisés :
Créer une classe non substantielle qui n'est qu'une collection de fonctions statiques liées (il s'agit fondamentalement d'un singleton, mais si elle est sans état et que les fonctions statiques opèrent strictement sur les paramètres plutôt que sur l'état de la classe, ce n'est pas une approche aussi déraisonnable que ce que je suggérais précédemment, bien que l'utilisation d'une interface qui est injectée en fonction des dépendances rende souvent plus facile la maintenance de l'API lorsque l'implémentation nécessite un plus grand nombre de dépendances ou d'autres formes de contexte).
Lorsqu'il existe plusieurs façons de créer l'objet, un constructeur privé peut faciliter la compréhension des différentes façons de le construire (par exemple, celle qui est la plus lisible pour vous ). new ArrayList(5)
o ArrayList.createWithCapacity(5)
, ArrayList.createWithContents(5)
, ArrayList.createWithInitialSize(5)
). En d'autres termes, un constructeur privé vous permet de fournir des fonctions d'usine dont les noms sont plus compréhensibles, et le fait de rendre le constructeur privé garantit que les gens n'utilisent que les noms les plus évidents. Ceci est aussi couramment utilisé avec le modèle du bâtisseur . Par exemple :
MyClass myVar = MyClass
.newBuilder()
.setOption1(option1)
.setOption2(option2)
.build();
Du point de vue de la testabilité - ils représentent un état global, qui est difficile à prévoir (et à tester)
@Vuntic, la réponse courte est que les singletons résultent en un état mutable partagé et, plus important encore, l'intégration de l'aspect singleton dans l'API la rend inflexible, difficile à tester et rend les choses difficiles lorsqu'il s'avère que l'hypothèse du singleton n'est pas correcte. S'il est bon d'avoir des singletons dans le sens où vous n'instanciez l'objet qu'une seule fois, l'application du caractère singleton via un constructeur privé et une fonction d'instanciation statique conduit à une conception incroyablement désordonnée et fragile. Une meilleure approche consiste à transmettre l'interface à laquelle le singleton se conforme...
Je m'attendais à ce que quelqu'un l'ait mentionné (le 2ème point), mais il y a trois utilisations des constructeurs privés :
pour empêcher l'instanciation en dehors de l'objet, dans les cas suivants :
pour éviter la sublcassation (extension). Si vous n'avez qu'un constructeur privé, aucune classe ne peut étendre votre classe, car elle ne peut pas appeler le constructeur de la classe. super()
Constructeur. Il s'agit en quelque sorte d'un synonyme de final
Constructeurs surchargés - en raison de la surcharge des méthodes et des constructeurs, certains peuvent être privés et d'autres publics. En particulier dans le cas où il y a une classe non publique que vous utilisez dans vos constructeurs, vous pouvez créer un constructeur public qui crée une instance de cette classe et la passe ensuite à un constructeur privé.
En Java, le mot clé "final" est utilisé pour empêcher le sous-classement ; il n'est pas nécessaire de rendre le constructeur privé pour cela.
Ce n'est pas nécessaire, mais vous pouvez le faire. J'ai mentionné le final
comme moyen d'y parvenir.
Les "cas suivants" sont nécessairement incomplets mais en tout cas non pertinents. Il empêche l'instanciation à partir de l'extérieur du classe, sur tous des cas, pas seulement ceux énumérés ici.
Oui.
Cela vous permet de contrôler la façon dont la classe est instanciée. Si vous rendez le constructeur privé, puis créez une méthode de constructeur visible qui renvoie des instances de la classe, vous pouvez faire des choses comme limiter le nombre de créations (typiquement, garantir qu'il y a exactement une instance) ou recycler des instances ou d'autres tâches liées à la construction.
Faire new x()
ne revient jamais null
mais en utilisant le modèle de l'usine, vous pouvez rendre null
ou même de renvoyer des sous-types différents.
Vous pouvez également l'utiliser pour une classe qui n'a pas de membres d'instance ou de propriétés, seulement des membres statiques, comme dans une classe de fonction utilitaire.
Mais vous pouvez garder la trace du nombre d'instances en utilisant simplement une variable statique ; il n'est pas nécessaire de rendre le constructeur privé pour cela.
@michael en effet vous pouvez, mais ce n'est pas aussi élégant, et la restriction n'est pas aussi évidente pour les utilisateurs de la classe.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
10 votes
Il convient de noter que la plupart des réponses données jusqu'à présent ne considèrent que le cas où l'on a uniquement des constructeurs privés. Vous pouvez avoir des constructeurs publics et privés dans la même classe, pour les raisons expliquées dans la réponse de Michael Aaron Safyan.
0 votes
@ChristianSemrau Je suis en train de regarder le bocal pour
lwjgl3
(beta) via Eclipse, et j'ai trouvé un constructeur privé dans le fichierorg.lwjgl.Version
. Ce qui m'amène ici. Cette classe a aussi sa propremain
de manière intéressante. Java est bizarre.0 votes
Que s'est-il passé quand vous l'avez essayé ? Ou que vous l'avez regardé ? Y avait-il une raison de se méfier de la compilation ou de JLS ?