À quoi bon rendre un constructeur privé dans une classe?
pourquoi rendre le constructeur privé en classe? Comme nous avons toujours besoin que le constructeur soit public.
23 réponses
Certaines raisons, vous pouvez avoir besoin constructeur privé:
- le constructeur n'est accessible qu'à partir de static factory method à l'intérieur de la classe elle-même. Singleton peut aussi appartenir à cette catégorie.
- classe d'utilité , qui ne contient que des méthodes statiques.
en fournissant un constructeur privé vous empêchez les instances de classe d'être créées dans un autre endroit que cette classe même. Il existe plusieurs cas d'utilisation pour fournir un tel constructeur.
A. vos instances de classe sont créées selon la méthode static
. La méthode static
est alors déclarée comme public
.
class MyClass()
{
private:
MyClass() { }
public:
static MyClass * CreateInstance() { return new MyClass(); }
};
B. votre classe est une singleton . Cela signifie, pas plus d'une instance de votre la classe existe dans le programme.
class MyClass()
{
private:
MyClass() { }
public:
MyClass & Instance()
{
static MyClass * aGlobalInst = new MyClass();
return *aGlobalInst;
}
};
C. (Ne s'applique qu'au prochain standard C++0x) vous avez plusieurs constructeurs. Certains d'entre eux sont déclarés public
, d'autres private
. Pour réduire la taille du code, les constructeurs publics "appellent" les constructeurs privés qui, à leur tour, font tout le travail. Vos constructeurs public
sont ainsi appelés délégant constructeurs:
class MyClass
{
public:
MyClass() : MyClass(2010, 1, 1) { }
private:
MyClass(int theYear, int theMonth, int theDay) { /* do real work */ }
};
D. vous voulez limiter l'objet copie (par exemple, à cause de l'utilisation d'une ressource partagée):
class MyClass
{
SharedResource * myResource;
private:
MyClass(const MyClass & theOriginal) { }
};
E. votre classe est une classe utilitaire . Cela signifie qu'il ne contient que des membres static
. Dans ce cas, aucune instance objet ne doit jamais être créée dans le programme.
pour laisser une" porte dérobée " qui permet à une autre classe/fonction d'amis de construire un objet d'une manière interdite à l'utilisateur. Un exemple qui vient à l'esprit serait un conteneur construisant un itérateur (C++):
Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
// and Container is a friend of Iterator.
tout le monde est coincé sur la chose Singleton, wow.
autres choses:
- empêcher les gens de créer votre classe sur la pile; faire des constructeurs privés et seulement remettre des pointeurs par une méthode d'usine.
- empêcher la création de copys de la classe (private copy constructor)
cela peut être très utile pour un constructeur qui contient un code commun; les constructeurs privés peuvent être appelés par d'autres constructeurs, en utilisant le 'Ceci(...);' notation. En faisant le code d'initialisation commun dans un constructeur privé( ou protégé), vous précisez aussi explicitement qu'il est appelé seulement pendant la construction, ce qui n'est pas le cas s'il s'agit simplement d'une méthode:
public class Point {
public Point() {
this(0,0); // call common constructor
}
private Point(int x,int y) {
m_x = x; m_y = y;
}
};
il y a des cas où vous pourriez ne pas vouloir utiliser un constructeur public; par exemple si vous voulez une classe singleton.
si vous écrivez un assemblage utilisé par des tiers, il peut y avoir un certain nombre de classes internes que vous voulez seulement créer par votre assemblage et ne pas être instancié par les utilisateurs de votre assemblage.
cela garantit que vous (la classe avec le constructeur privé) contrôlez comment le contructeur est appelé.
un exemple : une méthode d'usine statique sur la classe pourrait retourner des objets comme la méthode d'usine choisit de les allouer (comme une usine singleton par exemple).
nous pouvons aussi avoir un constructeur privé, avant la création de l'objet par une classe spécifique seulement(Pour des raisons de sécurité).
une façon de le faire est d'avoir une classe d'amis.
c++ exemple:
class ClientClass;
class SecureClass
{
private:
SecureClass(); // Constructor is private.
friend class ClientClass; // All methods in
//ClientClass have access to private
// & protected methods of SecureClass.
};
class ClientClass
{
public:
ClientClass();
SecureClass* CreateSecureClass()
{
return (new SecureClass()); // we can access
// constructor of
// SecureClass as
// ClientClass is friend
// of SecureClass.
}
};
Note: Note: Seulement ClientClass (car il est ami de SecureClass) peut appeler le constructeur de SecureClass.
j'ai vu une question de vous abordant la même question.
simplement si vous ne voulez pas permettre aux autres de créer des instances, alors gardez le constuctor dans une portée limitée. L'application pratique (Un exemple) est un singleton.
Vous ne devrait pas faire le constructeur privé. Période. Faire protégées, de sorte que vous pouvez étendre la classe, si vous en avez besoin.
Edit: je suis debout par qui, n'importe comment beaucoup de downvotes vous jeter sur cette. Vous coupez le potentiel de développement futur du code. Si d'autres utilisateurs ou programmeurs sont vraiment déterminés à étendre la classe, alors ils vont juste changer le constructeur à protégé dans la source ou bytecode. Vous n'aurez rien accompli d'autre que de rendre leur vie un peu plus difficile. Incluez un avertissement dans les commentaires de votre constructeur, et laissez tomber.
S'il s'agit d'une classe d'utilité, la solution la plus simple, la plus correcte et la plus élégante est de marquer toute la classe" final statique " pour éviter l'extension. Il ne sert à rien de simplement marquer le constructeur privé; un utilisateur vraiment déterminé peut toujours utiliser la réflexion pour obtenir le constructeur.
Valide utilise:
- Une bonne utilisation d'un
protected
le constructeur doit forcer l'utilisation de méthodes de fabrique, qui vous permettent de instanciation limite ou pool & reuse ressources coûteuses (connexions DB), ressources autochtones). - Singletons (généralement pas une bonne pratique, mais il est parfois nécessaire)
Constructor est privé pour un but comme quand vous avez besoin d'implémenter singleton ou de limiter le nombre d'objet d'une classe. Par exemple dans la mise en œuvre singleton nous devons rendre le constructeur privé
#include<iostream>
using namespace std;
class singletonClass
{
static int i;
static singletonClass* instance;
public:
static singletonClass* createInstance()
{
if(i==0)
{
instance =new singletonClass;
i=1;
}
return instance;
}
void test()
{
cout<<"successfully created instance";
}
};
int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{
singletonClass *temp=singletonClass::createInstance();//////return instance!!!
temp->test();
}
encore une fois si vous voulez limiter la création de l'objet jusqu'à 10 puis utiliser le suivant
#include<iostream>
using namespace std;
class singletonClass
{
static int i;
static singletonClass* instance;
public:
static singletonClass* createInstance()
{
if(i<10)
{
instance =new singletonClass;
i++;
cout<<"created";
}
return instance;
}
};
int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{
singletonClass *temp=singletonClass::createInstance();//return an instance
singletonClass *temp1=singletonClass::createInstance();///return another instance
}
Merci
Vous pouvez avoir plus d'un constructeur. C++ fournit un constructeur par défaut et un constructeur de copie par défaut si vous ne fournissez pas explicitement. Supposons que vous ayez une classe qui ne peut être construite qu'en utilisant un constructeur paramétré. Peut-être qu'il a initialisé des variables. Si un utilisateur utilise ensuite cette classe sans constructeur, ils peuvent causer de problèmes. Une bonne règle générale: si l'implémentation par défaut n'est pas valide, rendez le constructeur par défaut et le constructeur de copie privés et ne le faites pas. fournir une mise en œuvre:
class C
{
public:
C(int x);
private:
C();
C(const C &);
};
Utiliser le compilateur pour empêcher les utilisateurs d'utiliser l'objet avec les constructeurs par défaut qui ne sont pas valides.
voici quelques-unes des utilisations du constructeur privé:
- Modèle De Conception Singleton
- limiter le nombre d'instances créées
- donner un nom significatif pour la création d'objet en utilisant la méthode d'usine statique
- Classe D'utilité statique ou classe constante
- pour empêcher le sous-classement
- dessin du constructeur et donc pour création de classes immuables
quand 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
, toute la fonction dans ce paquet est static
, toutes les fonctions peuvent être appelées sans créer une instance de math
, donc le constructeur est annoncé comme statique.
citant Java efficace , vous pouvez avoir une classe avec le constructeur privé pour avoir une classe d'utilité qui définit les constantes (comme champs finaux statiques).
( EDIT: selon le commentaire, c'est quelque chose qui pourrait être applicable qu'avec Java, je suis pas si cette construction est applicable/nécessaires dans d'autres langages à objets (par exemple, C++))
exemple ci-dessous:
EDIT_1: Again, below explanation is applicable in Java : (and referring from the book, Effective Java)
An instantiation of utility class like the one below ,though not harmful, doesn't serve any purpose since they are not designed to be instantiated.
For example, say there is no private Constructor for class Constants.
A code chunk like below is valid but doesn't better convey intention of
the user of Constants class
unit = (this.length)/new Constants().ADDRESS_UNIT;
en contraste avec le code comme
unit = (this.length)/Constants.ADDRESS_UNIT;
aussi je pense qu'un constructeur privé communique l'intention du concepteur du constantes (disons) de la meilleure classe.
Java fournit un constructeur public par défaut sans paramètre si aucun constructeur est fourni, et si votre intention est d'empêcher l'instanciation puis un constructeur privé est nécessaire.
on ne peut pas marquer une classe supérieure statique et même une classe finale peut être instanciée.
Utilitaire de classes ont les constructeurs privés. Les utilisateurs des classes ne devraient pas pouvoir instancier ces classes:
public final class UtilityClass {
private UtilityClass() {}
public static utilityMethod1() {
...
}
}
vous pouvez empêcher qu'une classe soit instanciée librement. Voir le modèle de conception singleton comme un exemple. Afin de garantir l'unicité, vous ne pouvez laisser personne créer une instance de celui-ci: -)
L'une des utilisations importantes est dans la classe SingleTon
class Person
{
private Person()
{
//Its private, Hense cannot be Instantiated
}
public static Person GetInstance()
{
//return new instance of Person
// In here I will be able to access private constructor
}
};
est également adapté, si votre classe n'a que des méthodes statiques. I. e personne n'a besoin d'instancier votre classe
C'est vraiment une raison évidente: vous voulez construire un objet, mais c'est pas pratique de le faire (en terme d'interface) dans le constructeur.
l'exemple Factory
est assez évident, laissez-moi vous montrer l'idiome Named Constructor
.
dis que j'ai une classe Complex
qui peut représenter un nombre complexe.
class Complex { public: Complex(double,double); .... };
la question Est: le constructeur attend-il les parties réelles et imaginaires, ou le fait-il attend la norme et l'angle (coordonnées polaires)?
je peux changer l'interface pour la rendre plus facile:
class Complex
{
public:
static Complex Regular(double, double = 0.0f);
static Complex Polar(double, double = 0.0f);
private:
Complex(double, double);
}; // class Complex
cela s'appelle l'idiome Named Constructor
: la classe ne peut être construite à partir de zéro en indiquant explicitement quel constructeur nous voulons 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 soit correctement contraint.
en plus des utilisations plus connues ...
pour mettre en œuvre la méthode objet modèle, que je résumerais comme:
"constructeur Privé, public la méthode statique"
"L'objet de la mise en œuvre, en fonction de l'interface"
si vous voulez implémenter une fonction en utilisant un objet, et que l'objet n'est pas utile en dehors de la réalisation d'un one-off calcul (par appel de méthode), puis vous avez un Throwaway Object . Vous pouvez encapsuler la création d'objet et l'appel de méthode dans une méthode statique, empêchant ce commun anti-modèle:
z = new A(x,y).call();
...le remplaçant par un appel de fonction (namespaced):
z = A.f(x,y);
l'appelant n'a jamais besoin de savoir ou de se soucier que vous utilisez un objet à l'interne, donnant une interface plus propre, et empêchant les déchets de l'objet suspendu utilisation approximative ou incorrecte de l'objet.
par exemple, si vous voulez casser un calcul à travers les méthodes foo
, bar
, et zork
, par exemple pour partager l'état sans avoir à passer beaucoup de valeurs dans et hors des fonctions, vous pouvez l'implémenter comme suit:
class A {
public static Z f(x, y) {
A a = new A(x, y);
a.foo();
a.bar();
return a.zork();
}
private A(X x, Y y) { /* ... */ };
}
Cette Méthode de l'Objet modèle est donné dans Smalltalk Meilleures Pratiques , Kent Beck, pages 34 à 37, où c'est la dernière étape de un refactoring modèle, en terminant:
- remplacer la méthode originale par une méthode qui crée une instance de la nouvelle classe, construite avec les paramètres et le récepteur de la méthode originale, et invoque "calculer".
ceci diffère significativement 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 singletons etc.), et peuvent vivre sur la pile, puisqu'ils ne s'échappent jamais.
Ce modèle est très utile dans bottoms-up OOP, où les objets sont utilisés pour simplifier la mise en œuvre de bas niveau, mais ne sont pas nécessairement exposés à l'extérieur, et contraste avec L'OOP Descendant qui est souvent présenté et commence avec des interfaces de haut niveau.
est Parfois utile si vous voulez contrôler quand et comment (et combien) les instances d'un objet sont créés.
entre autres, utilisé dans les modèles:
Singleton pattern
Builder pattern
sur l'utilisation de constructeurs privés pourrait également être d'accroître la lisibilité/maintenabilité face à la conception par domaine. Partir De "De Microsoft .NET - Architecing d'Applications pour l'Entreprise, 2e Édition":
var request = new OrderRequest(1234);
citation, " il y a deux problèmes ici. Tout d'abord, en regardant le code, on peut à peine deviner ce qui se passe sur. Une instance de OrderRequest est créée, mais pourquoi et en utilisant quelles données? C'est quoi, 1234? Ce conduit au deuxième problème: vous êtes violant le langage omniprésent du contexte limité. Le la langue dit probablement quelque chose comme ceci: un client peut émettre une demande d'ordre et est autorisé à spécifiez un ID d'achat. Si c'est le cas, voici une meilleure façon d'obtenir une nouvelle OrderRequest exemple:"
var request = OrderRequest.CreateForCustomer(1234);
où
private OrderRequest() { ... }
public OrderRequest CreateForCustomer (int customerId)
{
var request = new OrderRequest();
...
return request;
}
Je ne préconise pas cela pour chaque classe, mais pour le scénario DDD ci-dessus je pense qu'il est parfaitement sensé d'empêcher une création directe d'un nouvel objet.