oop - publicas - qué son métodos ya que se refiere con visibilidad de métodos
¿De qué sirve hacer que el constructor sea privado en una clase? (23)
A veces es útil si desea controlar cómo y cuándo (y cuántas) instancias de un objeto se crean.
Entre otros, usados en patrones:
Singleton pattern
Builder pattern
¿Por qué deberíamos hacer que el constructor sea privado en clase? Como siempre necesitamos que el constructor sea público.
Además de los usos más conocidos ...
Para implementar el patrón Objeto del método , que resumiría como:
"Constructor privado, método público estático"
"Objeto para la implementación, función para la 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 a un método), entonces tiene un objeto descartable . Puede encapsular la creación del objeto 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 importarle que esté utilizando un objeto internamente, lo que le permite tener una interfaz más limpia y evitar que el objeto se pierda o el uso incorrecto del objeto.
Por ejemplo, si desea dividir un cálculo en los métodos foo
, bar
y zork
, por ejemplo, para compartir estado sin tener que pasar muchos valores dentro y fuera de las funciones, puede implementarlo 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 por uno que cree una instancia de la nueva clase, construida con los parámetros y el receptor del método original, e invoque "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 singleton, etc.) y pueden vivir en la pila, ya que nunca escapan.
Este patrón es muy útil en POO de abajo arriba, donde los objetos se utilizan para simplificar la implementación de bajo nivel, pero no están necesariamente expuestos externamente, y contrasta con el POO de arriba hacia abajo que a menudo se presenta y comienza con interfaces de alto nivel.
Al proporcionar un constructor privado, evita que se creen instancias de clase en cualquier lugar que no sea esta clase. Hay varios casos de uso para proporcionar dicho constructor.
A. Sus instancias de clase se crean en un método static
. El método static
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 son 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 constructores public
se denominan así delegar constructores:
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 a que usa 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 miembros static
. En este caso, nunca se debe crear una instancia de objeto en el programa.
Algunas razones por las que puede necesitar un constructor privado:
- Solo se puede acceder al constructor desde el método de fábrica estático dentro de la clase misma. Singleton también puede pertenecer a esta categoría.
- Una clase de utilidad , que solo contiene métodos estáticos.
Citando de Effective Java , puede tener una clase con constructor privado para tener una clase de utilidad que define constantes (como campos finales estáticos).
( EDITAR: según el comentario esto es algo que podría ser aplicable solo con Java, no estoy al tanto de si esta construcción es aplicable / necesitada en otros lenguajes OO (por ejemplo, C ++))
Un ejemplo como a continuación:
public class Constants {
private Contants():
public static final int ADDRESS_UNIT = 32;
...
}
EDIT_1 : De nuevo, la explicación a continuación es aplicable en Java: (y hace referencia al libro, Java efectivo )
Una instancia 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 existe 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 Constants (say).
Java proporciona un constructor público sin parámetros predeterminado si no se proporciona un constructor, y si su intención es evitar la creación de instancias, se necesita un constructor privado.
No se puede marcar una clase estática de nivel superior e incluso se puede instanciar una clase final.
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, debemos 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();
}
De nuevo, si desea limitar la creación de objetos hasta 10, utilice la 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
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.
El uso de constructores privados también podría aumentar la legibilidad / mantenibilidad frente al diseño impulsado por el dominio. De "Microsoft .NET - Architecing Applications for the Enterprise, 2nd Edition":
var request = new OrderRequest(1234);
Cita: "Aquí hay dos problemas. Primero, al mirar el código, uno apenas puede adivinar qué está pasando. Se está creando una instancia de OrderRequest, pero ¿por qué y qué datos? ¿Qué es 1234? Esto lleva al segundo problema: está violando el lenguaje ubicuo del contexto delimitado. El lenguaje probablemente diga algo como esto: un cliente puede emitir una solicitud de pedido y puede especificar una 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 defiendo esto para cada clase, pero para el escenario DDD anterior creo que tiene mucho sentido evitar la creación directa de un nuevo objeto.
En algunos casos, es posible que no desee utilizar un constructor público; por ejemplo, si quieres una clase singleton.
Si está escribiendo un ensamblaje utilizado por terceros, podría haber una serie de clases internas que solo desea que el ensamblado cree y que los usuarios de su ensamblado no puedan crear.
En realidad, es una razón obvia: desea construir un objeto, pero no es práctico hacerlo (en términos de interfaz) dentro del constructor.
El ejemplo de Factory
es bastante obvio, permítanme demostrar el modismo de Named Constructor
.
Digamos que tengo un Complex
clases que puede representar un número complejo.
class Complex { public: Complex(double,double); .... };
La pregunta es: ¿el constructor espera las partes real e imaginaria, 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 conoce como el modismo del Named Constructor
: la clase solo se puede construir desde cero al declarar explícitamente qué constructor queremos usar.
Es un caso especial de muchos métodos de construcción. Los patrones de diseño proporcionan un buen número de formas para crear objetos: Builder
, Factory
, Abstract Factory
, ... y un constructor privado se asegurará de que el usuario esté debidamente restringido.
Es posible que desee evitar una instancia de una clase libremente. Vea el patrón de diseño singleton como un ejemplo. Para garantizar la singularidad, no puedes permitir que nadie cree una instancia de este :-)
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 según el método de fábrica elegido para asignarlos (como una fábrica de singleton, por ejemplo).
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 que el código de inicialización común en un constructor privado (o protegido), también se hace explícitamente claro que se llama solo durante la construcción, 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;
}
};
Estos son algunos de los usos del constructor privado:
- Patrón de diseño Singleton
- Para limitar el número de creación de instancia
- Para dar un nombre significativo para la creación de objetos usando el método de fábrica estático
- Static Utility Class o Constant Class
- Para evitar Subclases
- Patrón de diseño del constructor y por lo tanto para crear clases inmutables
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() {
...
}
}
No debes hacer que el constructor sea privado. Período. Haga que esté protegido, para que pueda extender la clase si es necesario.
Edit: estoy de acuerdo con eso, no importa cuántos votaciones negativas le hagas a esto. Estás cortando el potencial de desarrollo futuro en el código. Si otros usuarios o programadores están realmente decididos a extender la clase, entonces simplemente cambiarán el constructor a protegido en código fuente o byte. No habrás logrado nada más que hacer su vida un poco más difícil. Incluya una advertencia en los comentarios de su constructor, y déjelo 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 marcar solo el constructor privado; un usuario realmente determinado puede usar siempre la reflexión para obtener el constructor.
Usos válidos:
- Un buen uso de un constructor
protected
es forzar el uso de métodos de fábrica estáticos, que le permiten limitar la instanciación o agrupar y reutilizar recursos costosos (conexiones de bases de datos, recursos nativos). - Singletons (generalmente no es una buena práctica, pero a veces es necesaria)
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 puede construirse utilizando algún constructor parametrizado. Tal vez haya inicializado variables. Si un usuario utiliza esta clase sin ese constructor, pueden causar un sinfín de problemas. Una buena regla general: si la implementación predeterminada no es válida, haga que el constructor predeterminado y el de copia sean privados y no proporcione una implementación:
class C
{
public:
C(int x);
private:
C();
C(const C &);
};
Utilice el compilador para evitar que los usuarios usen el objeto con los constructores predeterminados que no son válidos.
Si es privado, entonces no puedes llamarlo ==> no puedes instanciar la clase. Útil en algunos casos, como un singleton.
Hay una discusión y algunos ejemplos más here .
También podemos tener un constructor privado, para evitar la creación del objeto por una clase específica solamente (por razones de seguridad).
Una forma de hacerlo es a través de una clase de amigos.
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.
Todo el mundo está atascado en Singleton, wow.
Otras cosas:
- Evite que las personas creen su clase en la pila; crea constructores privados y solo devuelve punteros a través de un método de fábrica.
- Evitar la creación de copys de la clase (constructor de copia privada)
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 tiene solo métodos estáticos. es decir, nadie necesita instanciar su clase
Vi una pregunta suya al abordar el mismo problema.
Simplemente, si no desea permitir que los demás creen instancias, mantenga el constuctor dentro de un alcance limitado. La aplicación práctica (Un ejemplo) es el patrón singleton.
cuando no desee que los usuarios creen instancias de esta clase o creen una clase que herede esta clase, como java.lang.math
, toda la función en este paquete es static
, todas las funciones se pueden llamar sin crear una instancia de math
, entonces el constructor se anuncia como estático.