Pourquoi devrions-nous rendre le constructeur privé en classe? Comme nous avons toujours besoin que le constructeur soit public.
134
Quelques raisons pour lesquelles vous pourriez avoir besoin d'un constructeur privé:
final
au niveau de la classe. Mettre un constructeur privé est pratiquement inutile pour cette raison.final
. C'est ce que Sun a fait pour la classe String et une partie raisonnable de l'API qui ne devrait pas être étendue.En fournissant un constructeur privé, vous empêchez la création d'instances de classe à un endroit autre que cette classe. Il existe plusieurs cas d'utilisation pour fournir un tel constructeur.
A. Vos instances de classe sont créées dans une
static
méthode. Lastatic
méthode est ensuite déclarée commepublic
.B. Votre classe est un singleton . Cela signifie qu'il n'existe pas plus d'une instance de votre classe dans le programme.
C. (S'applique uniquement au prochain standard C ++ 0x) Vous avez plusieurs constructeurs. Certains d'entre eux sont déclarés
public
, d'autresprivate
. Pour réduire la taille du code, les constructeurs publics «appellent» des constructeurs privés qui à leur tour font tout le travail. Vospublic
constructeurs sont donc appelés constructeurs délégués :D. Vous souhaitez limiter la copie d'objets (par exemple, en raison de l'utilisation d'une ressource partagée):
E. Votre classe est une classe utilitaire . Cela signifie qu'il ne contient que des
static
membres. Dans ce cas, aucune instance d'objet ne doit jamais être créée dans le programme.la source
Laisser une "porte dérobée" qui permet à une autre classe / fonction amie de construire un objet d'une manière interdite à l'utilisateur. Un exemple qui me vient à l'esprit serait un conteneur construisant un itérateur (C ++):
la source
friend
là où cela n'est pas justifié - et il y a de nombreux cas où c'est une mauvaise idée. Malheureusement, le message a été trop bien reçu et de nombreux développeurs n'apprennent jamais assez bien la langue pour comprendre que l'utilisation occasionnelle defriend
est non seulement acceptable, mais préférable . Votre exemple était exactement un tel cas. Un couplage fort délibéré n'est pas un crime, c'est une décision de conception.Tout le monde est coincé sur le truc Singleton, wow.
Autres choses:
la source
Cela peut être très utile pour un constructeur qui contient du code commun; les constructeurs privés peuvent être appelés par d'autres constructeurs, en utilisant le 'this (...);' notation. En rendant le code d'initialisation commun dans un constructeur privé (ou protégé), vous indiquez également explicitement qu'il n'est appelé que pendant la construction, ce qui n'est pas le cas s'il s'agissait simplement d'une méthode:
la source
Dans certains cas, vous ne souhaiterez peut-être pas utiliser de constructeur public; par exemple si vous voulez une classe singleton.
Si vous écrivez un assembly utilisé par des tiers, il peut y avoir un certain nombre de classes internes que vous souhaitez uniquement créer par votre assembly et ne pas être instanciées par les utilisateurs de votre assembly.
la source
Cela garantit que vous (la classe avec le constructeur privé) contrôlez la façon dont le constructeur est appelé.
Un exemple: une méthode de fabrique statique sur la classe peut renvoyer des objets lorsque la méthode de fabrique choisit de les allouer (comme une fabrique de singleton par exemple).
la source
On peut aussi avoir un constructeur privé, pour éviter la création de l'objet par une classe spécifique uniquement (pour des raisons de sécurité).
Une façon de le faire est d'avoir une classe d'amis.
Exemple C ++:
Remarque: Remarque: seul ClientClass (puisqu'il est ami de SecureClass) peut appeler le constructeur de SecureClass.
la source
Voici quelques-unes des utilisations du constructeur privé:
la source
lorsque vous ne voulez pas que les utilisateurs créent des instances de cette classe ou créent une classe qui hérite de cette classe, comme le
java.lang.math
, toutes les fonctions de ce package sontstatic
, toutes les fonctions peuvent être appelées sans créer d'instance demath
, donc le constructeur est annoncé comme statique .la source
Si c'est privé, vous ne pouvez pas l'appeler ==> vous ne pouvez pas instancier la classe. Utile dans certains cas, comme un singleton.
Il y a une discussion et quelques autres exemples ici .
la source
J'ai vu une question de votre part concernant le même problème.
Simplement si vous ne voulez pas permettre aux autres de créer des instances, gardez le constructeur dans une portée limitée. L'application pratique (un exemple) est le modèle singleton.
la source
Vous ne devez pas rendre le constructeur privé. Période. Rendez-le protégé afin de pouvoir étendre la classe si vous en avez besoin.
Edit: Je reste fidèle à cela, quel que soit le nombre de votes négatifs que vous lancez. Vous coupez le potentiel de développement futur du code. Si d'autres utilisateurs ou programmeurs sont vraiment déterminés à étendre la classe, ils changeront simplement le constructeur en protégé en source ou en bytecode. Vous n'aurez rien accompli d'autre que pour rendre leur vie un peu plus difficile. Incluez un avertissement dans les commentaires de votre constructeur et restez-en là.
S'il s'agit d'une classe utilitaire, la solution la plus simple, la plus correcte et la plus élégante est de marquer la classe entière comme "statique final" pour empêcher l'extension. Cela ne sert à rien de simplement marquer le constructeur comme privé; un utilisateur vraiment déterminé peut toujours utiliser la réflexion pour obtenir le constructeur.
Utilisations valides:
protected
constructeur est de forcer l'utilisation de méthodes de fabrique statiques, qui vous permettent de limiter l'instanciation ou de regrouper et de réutiliser des ressources coûteuses (connexions DB, ressources natives).la source
Le constructeur est privé dans un certain but, comme lorsque vous devez implémenter un singleton ou limiter le nombre d'objets d'une classe. Par exemple, dans l'implémentation singleton, nous devons rendre le constructeur privé
Encore une fois, si vous souhaitez limiter la création d'objets jusqu'à 10, utilisez ce qui suit
Merci
la source
Vous pouvez avoir plus d'un constructeur. C ++ fournit un constructeur par défaut et un constructeur de copie par défaut si vous n'en fournissez pas un explicitement. Supposons que vous ayez une classe qui ne peut être construite qu'à l'aide d'un constructeur paramétré. Peut-être qu'il a initialisé des variables. Si un utilisateur utilise ensuite cette classe sans ce constructeur, il ne peut causer aucun problème. Une bonne règle générale: si l'implémentation par défaut n'est pas valide, rendez privé le constructeur par défaut et le constructeur de copie et ne fournissez pas d'implémentation:
Utilisez le compilateur pour empêcher les utilisateurs d'utiliser l'objet avec les constructeurs par défaut qui ne sont pas valides.
la source
Citant Effective Java , vous pouvez avoir une classe avec un constructeur privé pour avoir une classe utilitaire qui définit des constantes (comme champs finaux statiques).
( EDIT: selon le commentaire, c'est quelque chose qui pourrait être applicable uniquement avec Java, je ne sais pas si cette construction est applicable / nécessaire dans d'autres langages OO (disons C ++))
Un exemple comme ci-dessous:
EDIT_1 : Encore une fois, l'explication ci-dessous est applicable en Java: (et faisant référence au livre, Effective Java )
Une instanciation de classe d'utilité comme celle ci-dessous, bien que non nuisible, ne sert à rien puisqu'elle n'est pas conçue pour être instanciée.
Par exemple, disons qu'il n'y a pas de constructeur privé pour les constantes de classe. Un bloc de code comme ci-dessous est valide mais ne transmet pas mieux l'intention de l'utilisateur de la classe Constants
contrairement au code comme
De plus, je pense qu'un constructeur privé exprime mieux l'intention du concepteur de la classe Constants (disons).
Java fournit un constructeur public sans paramètre par défaut si aucun constructeur n'est fourni, et si votre intention est d'empêcher l'instanciation, un constructeur privé est nécessaire.
On ne peut pas marquer une classe statique de niveau supérieur et même une classe finale peut être instanciée.
la source
Les classes d'utilité peuvent avoir des constructeurs privés. Les utilisateurs des classes ne doivent pas pouvoir instancier ces classes:
la source
Vous souhaiterez peut-être empêcher une classe d'être instanciée librement. Voir le modèle de conception singleton à titre d'exemple. Afin de garantir l'unicité, vous ne pouvez laisser personne en créer une instance :-)
la source
L'une des utilisations importantes est en classe SingleTon
C'est également approprié, si votre classe n'a que des méthodes statiques. c'est-à-dire que personne n'a besoin d'instancier votre classe
la source
C'est vraiment une raison évidente: vous voulez construire un objet, mais ce n'est pas pratique de le faire (en terme d'interface) dans le constructeur.
L'
Factory
exemple est assez évident, permettez-moi de démontrer l'Named Constructor
idiome.Disons que j'ai une classe
Complex
qui peut représenter un nombre complexe.La question est: le constructeur attend-il les parties réelles et imaginaires, ou attend-il la norme et l'angle (coordonnées polaires)?
Je peux changer l'interface pour le rendre plus facile:
C'est ce qu'on appelle l'
Named Constructor
idiome: la classe ne peut être construite à partir de rien en indiquant explicitement quel constructeur nous souhaitons utiliser.C'est un cas particulier de nombreuses méthodes de construction. Les modèles de conception offrent un bon nombre de façons de construire l' objet:
Builder
,Factory
,Abstract Factory
, ... et un constructeur privé veillera à ce que l'utilisateur est bien limitée.la source
En plus des utilisations les plus connues…
Pour implémenter le modèle d' objet de méthode , que je résumerais comme suit:
Si vous souhaitez implémenter une fonction à l'aide d'un objet, et que l'objet n'est pas utile en dehors d'un calcul ponctuel (par un appel de méthode), alors vous avez un objet Throwaway . Vous pouvez encapsuler la création d'objet et l'appel de méthode dans une méthode statique, évitant ainsi cet anti-pattern commun:
… En le remplaçant par un appel de fonction (avec un espace de nom):
L'appelant n'a jamais besoin de savoir ou de se soucier que vous utilisez un objet en interne, ce qui donne une interface plus propre et empêche les déchets de l'objet qui traînent ou une utilisation incorrecte de l'objet.
Par exemple, si vous souhaitez fractionner un calcul entre plusieurs méthodes
foo
,bar
etzork
, par exemple, partager un état sans avoir à passer de nombreuses valeurs dans et hors de fonctions, vous pouvez l'implémenter comme suit:Ce modèle d'objet de méthode est donné dans Smalltalk Best Practice Patterns , Kent Beck, pages 34–37, où il est la dernière étape d'un modèle de refactoring, se terminant:
Cela diffère considérablement des autres exemples ici: la classe est instanciable (contrairement à une classe utilitaire), mais les instances sont privées (contrairement aux méthodes d'usine, y compris les singletons, etc.), et peuvent vivre sur la pile, car elles ne s'échappent jamais.
Ce modèle est très utile dans la POO ascendante, où les objets sont utilisés pour simplifier l'implémentation de bas niveau, mais ne sont pas nécessairement exposés à l'extérieur, et contraste avec la POO descendante qui est souvent présentée et commence par des interfaces de haut niveau.
la source
C'est parfois utile si vous souhaitez contrôler comment et quand (et combien) d'instances d'un objet sont créées.
Entre autres, utilisé dans les modèles:
la source
L'utilisation de constructeurs privés pourrait également être d'augmenter la lisibilité / maintenabilité face à la conception axée sur le domaine. À partir de «Microsoft .NET - Applications d'architecture pour l'entreprise, 2e édition»:
Citation: "Il y a deux problèmes ici. Premièrement, quand on regarde le code, on peut difficilement deviner ce qui se passe. Une instance de OrderRequest est en cours de création, mais pourquoi et en utilisant quelles données? Qu'est-ce que 1234? Cela conduit au deuxième problème: vous ne respectez pas le langage omniprésent du contexte borné. Le langage dit probablement quelque chose comme ceci: un client peut émettre une demande de commande et est autorisé à spécifier un ID d'achat. Si tel est le cas, voici un meilleur moyen d'obtenir une nouvelle instance OrderRequest : "
où
Je ne préconise pas cela pour chaque classe, mais pour le scénario DDD ci-dessus, je pense qu'il est parfaitement logique d'empêcher la création directe d'un nouvel objet.
la source