Respuestas:
Algunas razones por las que puede necesitar un constructor privado:
finala nivel de clase. Poner un constructor privado es prácticamente inútil por este motivo.
final. Esto es lo que hizo Sun para la clase String, y una porción razonable de la API que no debe extenderse.
Al proporcionar un constructor privado, evita que se creen instancias de clase en cualquier lugar que no sea esta misma clase. Existen varios casos de uso para proporcionar dicho constructor.
A. Sus instancias de clase se crean en un staticmétodo. El staticmétodo se declara como public.
class MyClass()
{
private:
MyClass() { }
public:
static MyClass * CreateInstance() { return new MyClass(); }
};
B. Tu clase es un singleton . Esto significa que no existe más de una instancia de su clase en el programa.
class MyClass()
{
private:
MyClass() { }
public:
MyClass & Instance()
{
static MyClass * aGlobalInst = new MyClass();
return *aGlobalInst;
}
};
C. (Solo se aplica al próximo estándar C ++ 0x) Tiene varios constructores. Algunos de ellos están declarados public, otros private. Para reducir el tamaño del código, los constructores públicos 'llaman' a los constructores privados que a su vez hacen todo el trabajo. Sus publicconstructores se denominan así constructores delegadores :
class MyClass
{
public:
MyClass() : MyClass(2010, 1, 1) { }
private:
MyClass(int theYear, int theMonth, int theDay) { /* do real work */ }
};
D. Desea limitar la copia de objetos (por ejemplo, debido al uso de un recurso compartido):
class MyClass
{
SharedResource * myResource;
private:
MyClass(const MyClass & theOriginal) { }
};
E. Tu clase es una clase de utilidad . Eso significa que solo contiene staticmiembros. En este caso, nunca se debe crear una instancia de objeto en el programa.
Dejar una "puerta trasera" que permita que otra clase / función de amigo construya un objeto de una manera prohibida para el usuario. Un ejemplo que viene a la mente sería un contenedor que construye un iterador (C ++):
Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
// and Container is a friend of Iterator.
frienddonde no está garantizado, y hay muchos casos en los que es una mala idea. Lamentablemente, el mensaje ha sido muy bien recibido, y muchos desarrolladores nunca aprenden el idioma lo suficientemente bien como para comprender que el uso ocasional friendno solo es aceptable, sino preferible . Su ejemplo fue solo un caso así. El acoplamiento fuerte deliberado no es delito, es una decisión de diseño.
Todos están atrapados en lo de Singleton, wow.
Otras cosas:
Esto puede ser muy útil para un constructor que contiene código común; los constructores privados pueden ser llamados por otros constructores, usando 'this (...);' notación. Al hacer el código de inicialización común en un constructor privado (o protegido), también está dejando explícitamente claro que solo se llama durante la construcción, lo que no es así si fuera simplemente un método:
public class Point {
public Point() {
this(0,0); // call common constructor
}
private Point(int x,int y) {
m_x = x; m_y = y;
}
};
Hay algunos casos en los que es posible que no desee utilizar un constructor público; por ejemplo si quieres una clase singleton.
Si está escribiendo un ensamblado utilizado por terceros, podría haber una serie de clases internas que solo desea que su ensamblado cree y que los usuarios de su ensamblado no puedan crear instancias.
Esto garantiza que usted (la clase con constructor privado) controle cómo se llama al contructor.
Un ejemplo: un método de fábrica estático en la clase podría devolver objetos a medida que el método de fábrica elija asignarlos (como una fábrica de singleton, por ejemplo).
También podemos tener un constructor privado, para prevenir la creación del objeto solo por una clase específica (por razones de seguridad).
Ejemplo de C ++:
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.
}
};
Nota: Nota: Solo ClientClass (ya que es amigo de SecureClass) puede llamar al Constructor de SecureClass.
Estos son algunos de los usos del constructor privado:
cuando no desea que los usuarios creen instancias de esta clase o creen una clase que herede esta clase, como java.lang.math, todas las funciones en este paquete son static, todas las funciones se pueden invocar sin crear una instancia math, por lo que el constructor se anuncia como estático .
Vi una pregunta tuya que abordaba el mismo problema.
Simplemente, si no desea permitir que los demás creen instancias, mantenga el constructor dentro de un alcance limitado. La aplicación práctica (un ejemplo) es el patrón singleton.
No deberías hacer que el constructor sea privado. Período. Hazlo protegido, para que puedas extender la clase si lo necesitas.
Editar: Estoy de acuerdo con eso, no importa cuántos votos negativos arrojes a esto. Estás cortando el potencial para el desarrollo futuro del código. Si otros usuarios o programadores están realmente decididos a extender la clase, simplemente cambiarán el constructor a protegido en código fuente o bytecode. No habrá logrado nada más que hacer su vida un poco más difícil. Incluye una advertencia en los comentarios de tu constructor y déjalo así.
Si se trata de una clase de utilidad, la solución más simple, más correcta y más elegante es marcar toda la clase como "estática final" para evitar la extensión. No sirve de nada simplemente marcar el constructor privado; un usuario realmente determinado siempre puede usar la reflexión para obtener el constructor.
protected
constructor es forzar el uso de métodos de fábrica estáticos, que le permiten limitar la creación de instancias o agrupar y reutilizar recursos caros (conexiones de base de datos, recursos nativos).Constructor es privado para algún propósito, como cuando necesita implementar singleton o limitar el número de objetos de una clase. Por ejemplo, en la implementación de singleton tenemos que hacer que el constructor sea privado
#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();
}
Nuevamente, si desea limitar la creación de objetos hasta 10, use lo siguiente
#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
}
Gracias
Puedes tener más de un constructor. C ++ proporciona un constructor predeterminado y un constructor de copia predeterminado si no proporciona uno explícitamente. Supongamos que tiene una clase que solo se puede construir utilizando algún constructor parametrizado. Quizás inicializó variables. Si un usuario usa esta clase sin ese constructor, puede causar un sinfín de problemas. Una buena regla general: si la implementación predeterminada no es válida, haga que tanto el constructor predeterminado como el de copia sean privados y no proporcione una implementación:
class C
{
public:
C(int x);
private:
C();
C(const C &);
};
Use el compilador para evitar que los usuarios usen el objeto con los constructores predeterminados que no son válidos.
Citando desde Java efectivo , puede tener una clase con un constructor privado para tener una clase de utilidad que defina constantes (como campos finales estáticos).
( EDITAR: según el comentario, esto es algo que podría ser aplicable solo con Java, no sé si esta construcción es aplicable / necesaria en otros lenguajes OO (por ejemplo, C ++))
Un ejemplo como el siguiente:
public class Constants {
private Contants():
public static final int ADDRESS_UNIT = 32;
...
}
EDIT_1 : Nuevamente, la explicación a continuación es aplicable en Java: (y haciendo referencia al libro, Java efectivo )
Una instanciación de la clase de utilidad como la siguiente, aunque no es dañina, no sirve para nada, ya que no están diseñados para ser instanciados.
Por ejemplo, supongamos que no hay un constructor privado para las constantes de clase. Un fragmento de código como el siguiente es válido pero no transmite mejor la intención del usuario de la clase Constantes
unit = (this.length)/new Constants().ADDRESS_UNIT;
en contraste con el código como
unit = (this.length)/Constants.ADDRESS_UNIT;
También creo que un constructor privado transmite mejor la intención del diseñador de la clase Constantes (digamos).
Java proporciona un constructor público sin parámetros predeterminado si no se proporciona ningún constructor, y si su intención es evitar la creación de instancias, se necesita un constructor privado.
No se puede marcar una clase de nivel superior estática e incluso se puede instanciar una clase final.
Las clases de utilidad podrían tener constructores privados. Los usuarios de las clases no deberían poder crear instancias de estas clases:
public final class UtilityClass {
private UtilityClass() {}
public static utilityMethod1() {
...
}
}
Uno de los usos importantes es en la clase 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
}
};
También es adecuado, si su clase solo tiene métodos estáticos. es decir, nadie necesita crear una instancia de tu clase
Realmente es una razón obvia: desea construir un objeto, pero no es práctico hacerlo (en términos de interfaz) dentro del constructor.
El Factoryejemplo es bastante obvio, déjame demostrar el Named Constructoridioma.
Digamos que tengo una clase Complexque puede representar un número complejo.
class Complex { public: Complex(double,double); .... };
La pregunta es: ¿el constructor espera las partes reales e imaginarias, o espera la norma y el ángulo (coordenadas polares)?
Puedo cambiar la interfaz para que sea más fácil:
class Complex
{
public:
static Complex Regular(double, double = 0.0f);
static Complex Polar(double, double = 0.0f);
private:
Complex(double, double);
}; // class Complex
Esto se llama Named Constructormodismo: la clase solo se puede construir desde cero al indicar explícitamente qué constructor queremos usar.
Es un caso especial de muchos métodos de construcción. Los patrones de diseño son un buen número de formas de acumulación de objetos: Builder, Factory, Abstract Factory, ... y un constructor privado se asegurará de que el usuario se ve limitada correctamente.
Además de los usos más conocidos ...
Para implementar el patrón Object Object , que resumiría como:
"Constructor privado, método estático público"
"Objeto para implementación, función para interfaz"
Si desea implementar una función usando un objeto, y el objeto no es útil fuera de hacer un cálculo único (mediante una llamada al método), entonces tiene un Objeto desechable . Puede encapsular la creación de objetos y la llamada al método en un método estático, evitando este antipatrón común:
z = new A(x,y).call();
... reemplazándolo con una llamada de función (espacio de nombres):
z = A.f(x,y);
La persona que llama nunca necesita saber o preocuparse de que esté utilizando un objeto internamente, produciendo una interfaz más limpia y evitando que la basura del objeto cuelgue o el uso incorrecto del objeto.
Por ejemplo, si desea dividir un cálculo entre métodos foo , bary zork, por ejemplo, para la participación del estado sin tener que pasar muchos valores dentro y fuera de funciones, se podría implementar de la siguiente manera:
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) { /* ... */ };
}
Este patrón de objeto de método se da en Smalltalk Best Practice Patterns , Kent Beck, páginas 34–37, donde es el último paso de un patrón de refactorización, que termina:
- Reemplace el método original con uno que cree una instancia de la nueva clase, construida con los parámetros y el receptor del método original, e invoca "calcular".
Esto difiere significativamente de los otros ejemplos aquí: la clase es instanciable (a diferencia de una clase de utilidad), pero las instancias son privadas (a diferencia de los métodos de fábrica, incluidos los singletons, etc.) y pueden vivir en la pila, ya que nunca escapan.
Este patrón es muy útil en la OOP de abajo hacia arriba, donde los objetos se usan para simplificar la implementación de bajo nivel, pero no necesariamente están expuestos externamente, y contrasta con la OOP de arriba hacia abajo que a menudo se presenta y comienza con interfaces de alto nivel.
A veces es útil si desea controlar cómo y cuándo se crean (y cuántas) instancias de un objeto.
Entre otros, utilizados en patrones:
Singleton pattern
Builder pattern
El uso de constructores privados también podría ser aumentar la legibilidad / mantenibilidad frente al diseño dirigido por el dominio. De "Microsoft .NET - Aplicaciones de arquitectura para la empresa, 2ª edición":
var request = new OrderRequest(1234);
Cita: "Hay dos problemas aquí. Primero, cuando se mira el código, uno apenas puede adivinar lo que está sucediendo. Se está creando una instancia de OrderRequest, pero ¿por qué y con qué datos? ¿Qué es 1234? Esto lleva al segundo problema: está violando el lenguaje ubicuo del contexto acotado. El lenguaje probablemente dice algo como esto: un cliente puede emitir una solicitud de pedido y se le permite especificar un ID de compra. Si ese es el caso, esta es una mejor manera de obtener una nueva instancia de OrderRequest : "
var request = OrderRequest.CreateForCustomer(1234);
dónde
private OrderRequest() { ... }
public OrderRequest CreateForCustomer (int customerId)
{
var request = new OrderRequest();
...
return request;
}
No estoy abogando por esto para cada clase, pero para el escenario DDD anterior, creo que tiene mucho sentido evitar la creación directa de un nuevo objeto.