Respostas:
Algumas razões pelas quais você pode precisar de construtor privado:
final
no nível da classe. Colocar o construtor privado é praticamente inútil por esse motivo.
final
. Foi isso que a Sun fez pela classe String e uma parte razoável da API que não deve ser estendida.
Ao fornecer um construtor privado, você evita que instâncias de classe sejam criadas em qualquer lugar que não seja essa mesma classe. Existem vários casos de uso para fornecer esse construtor.
A. Suas instâncias de classe são criadas em um static
método. O static
método é então declarado como public
.
class MyClass()
{
private:
MyClass() { }
public:
static MyClass * CreateInstance() { return new MyClass(); }
};
B. Sua turma é única . Isso significa que não há mais de uma instância da sua classe no programa.
class MyClass()
{
private:
MyClass() { }
public:
MyClass & Instance()
{
static MyClass * aGlobalInst = new MyClass();
return *aGlobalInst;
}
};
C. (Aplica-se apenas ao próximo padrão C ++ 0x) Você tem vários construtores. Alguns deles são declarados public
, outros private
. Para reduzir o tamanho do código, os construtores públicos 'chamam' construtores privados que, por sua vez, fazem todo o trabalho. Seus public
construtores são chamados de delegadores de construção:
class MyClass
{
public:
MyClass() : MyClass(2010, 1, 1) { }
private:
MyClass(int theYear, int theMonth, int theDay) { /* do real work */ }
};
D. Você deseja limitar a cópia do objeto (por exemplo, devido ao uso de um recurso compartilhado):
class MyClass
{
SharedResource * myResource;
private:
MyClass(const MyClass & theOriginal) { }
};
E. Sua classe é uma classe de utilidade . Isso significa que ele contém apenas static
membros. Nesse caso, nenhuma instância do objeto deve ser criada no programa.
Deixar uma "porta dos fundos" que permita que outra classe / função de amigo construa um objeto de uma maneira proibida pelo usuário. Um exemplo que vem à mente seria um contêiner que constrói um iterador (C ++):
Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
// and Container is a friend of Iterator.
friend
lo onde não se justifica - e há muitos casos em que é uma má ideia. Infelizmente, a mensagem foi muito bem recebida e muitos desenvolvedores nunca aprendem a linguagem o suficiente para entender que o uso ocasional de friend
não é apenas aceitável, mas preferível . Seu exemplo foi exatamente esse caso. Um acoplamento forte e deliberado não é crime, é uma decisão de design.
Todo mundo está preso na coisa Singleton, uau.
Outras coisas:
Isso pode ser muito útil para um construtor que contém código comum; construtores privados podem ser chamados por outros construtores, usando o 'this (...);' notação. Ao tornar o código de inicialização comum em um construtor privado (ou protegido), você também deixa explicitamente claro que ele é chamado apenas durante a construção, o que não acontece se fosse simplesmente um 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;
}
};
Existem alguns casos em que você pode não querer usar um construtor público; por exemplo, se você deseja uma classe singleton.
Se você estiver escrevendo uma montagem usada por terceiros, pode haver várias classes internas que você deseja criar apenas pela sua montagem e não serem instanciadas pelos usuários da sua montagem.
Isso garante que você (a classe com construtor privado) controle como o contratante é chamado.
Um exemplo: um método de fábrica estático na classe pode retornar objetos à medida que o método de fábrica escolhe alocá-los (como uma fábrica de singleton, por exemplo).
Também podemos ter construtor privado, para garantir a criação do objeto apenas por uma classe específica (por razões de segurança).
Exemplo 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: Somente o ClientClass (por ser amigo do SecureClass) pode chamar o SecureClass's Constructor.
Aqui estão alguns dos usos do construtor privado:
quando você não deseja que os usuários criem instâncias dessa classe ou criem uma classe que herda essa classe, como java.lang.math
todas as funções deste pacote static
, todas as funções podem ser chamadas sem criar uma instância de math
, portanto, o construtor é anunciado como estático .
Vi uma pergunta sua abordando o mesmo problema.
Simplesmente, se você não deseja permitir que os outros criem instâncias, mantenha o construtor dentro de um escopo limitado. A aplicação prática (um exemplo) é o padrão singleton.
Você não deve tornar o construtor privado. Período. Torne-o protegido, para que você possa estender a classe, se necessário.
Edit: Eu estou de pé por isso, não importa quantos votos negativos você jogue com isso. Você está cortando o potencial de desenvolvimento futuro do código. Se outros usuários ou programadores estiverem realmente determinados a estender a classe, eles mudarão o construtor para protegido na origem ou no bytecode. Você não terá conseguido nada além de dificultar a vida deles. Inclua um aviso nos comentários do construtor e deixe por isso mesmo.
Se for uma classe de utilidade, a solução mais simples, correta e elegante é marcar toda a classe como "estática final" para impedir a extensão. Não adianta apenas marcar o construtor como privado; um usuário realmente determinado sempre pode usar a reflexão para obter o construtor.
protected
construtor é forçar o uso de métodos estáticos de fábrica, que permitem limitar a instanciação ou agrupar e reutilizar recursos caros (conexões de banco de dados, recursos nativos).O construtor é privado para algum propósito, como quando você precisa implementar singleton ou limitar o número de objetos de uma classe. Por exemplo, na implementação de singleton, temos que tornar o construtor 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();
}
Novamente, se você quiser limitar a criação de objetos em até 10, use o seguinte
#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
}
obrigado
Você pode ter mais de um construtor. O C ++ fornece um construtor padrão e um construtor de cópia padrão, se você não fornecer um explicitamente. Suponha que você tenha uma classe que só pode ser construída usando algum construtor parametrizado. Talvez tenha inicializado variáveis. Se um usuário usar essa classe sem esse construtor, ele poderá causar problemas sem fim. Uma boa regra geral: se a implementação padrão não for válida, torne o construtor padrão e de cópia privado e não forneça uma implementação:
class C
{
public:
C(int x);
private:
C();
C(const C &);
};
Use o compilador para impedir que os usuários usem o objeto com os construtores padrão que não são válidos.
Citando em Java Efetivo , você pode ter uma classe com construtor privado para ter uma classe de utilitário que define constantes (como campos finais estáticos).
( EDIT: Conforme o comentário, isso é algo que pode ser aplicável apenas ao Java, não sei se essa construção é aplicável / necessária em outras linguagens OO (por exemplo, C ++))
Um exemplo como abaixo:
public class Constants {
private Contants():
public static final int ADDRESS_UNIT = 32;
...
}
EDIT_1 : Novamente, a explicação abaixo é aplicável em Java: (e referindo-se ao livro, Java efetivo )
Uma instanciação de classe de utilidade como a abaixo, embora não seja prejudicial, não serve a nenhum propósito, pois não foi projetada para ser instanciada.
Por exemplo, digamos que não haja Construtor privado para as constantes da classe. Um pedaço de código como abaixo é válido, mas não transmite melhor a intenção do usuário da classe Constants
unit = (this.length)/new Constants().ADDRESS_UNIT;
em contraste com código como
unit = (this.length)/Constants.ADDRESS_UNIT;
Também acho que um construtor privado transmite melhor a intenção do projetista da classe Constants (digamos).
Java fornece um construtor público sem parâmetros padrão, se nenhum construtor for fornecido, e se sua intenção for impedir a instanciação, será necessário um construtor privado.
Não se pode marcar uma classe de nível superior como estática e até uma classe final pode ser instanciada.
As classes de utilitário podem ter construtores particulares. Os usuários das classes não devem poder instanciar essas classes:
public final class UtilityClass {
private UtilityClass() {}
public static utilityMethod1() {
...
}
}
Um dos usos importantes está na 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
}
};
Também é adequado, se sua classe tiver apenas métodos estáticos. ou seja, ninguém precisa instanciar sua classe
É realmente uma razão óbvia: você deseja construir um objeto, mas não é prático fazê-lo (em termos de interface) dentro do construtor.
O Factory
exemplo é bastante óbvio, deixe-me demonstrar o Named Constructor
idioma.
Digamos que eu tenha uma classe Complex
que possa representar um número complexo.
class Complex { public: Complex(double,double); .... };
A questão é: o construtor espera as partes reais e imaginárias ou a norma e o ângulo (coordenadas polares)?
Eu posso mudar a interface para facilitar:
class Complex
{
public:
static Complex Regular(double, double = 0.0f);
static Complex Polar(double, double = 0.0f);
private:
Complex(double, double);
}; // class Complex
Isso é chamado de Named Constructor
idioma: a classe só pode ser construída do zero, declarando explicitamente qual construtor queremos usar.
É um caso especial de muitos métodos de construção. Os padrões de projeto fornecem um bom número de maneiras de objeto de construção: Builder
, Factory
, Abstract Factory
, ... e um construtor privado irá garantir que o usuário está devidamente restrito.
Além dos usos mais conhecidos…
Para implementar o padrão Object Object , que resumiria como:
"Construtor privado, método estático público"
"Objeto para implementação, função para interface"
Se você deseja implementar uma função usando um objeto, e o objeto não for útil fora de fazer um cálculo único (por uma chamada de método), você terá um Objeto Throwaway . Você pode encapsular a criação do objeto e a chamada do método em um método estático, impedindo esse antipadrão comum:
z = new A(x,y).call();
… Substituindo-o por uma chamada de função (com espaço para nome):
z = A.f(x,y);
O chamador nunca precisa saber ou se importar com o uso interno de um objeto, produzindo uma interface mais limpa e evitando o lixo do objeto pendurado ou o uso incorreto do objeto.
Por exemplo, se você quer terminar uma computação através de métodos foo
, bar
e zork
, por exemplo para estado share sem ter que passar muitos valores dentro e fora de funções, você pode implementá-lo da seguinte forma:
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 padrão de Objeto de método é fornecido em Smalltalk Best Practice Patterns , Kent Beck, páginas 34–37, onde é a última etapa de um padrão de refatoração, terminando:
- Substitua o método original por um que crie uma instância da nova classe, construída com os parâmetros e o receptor do método original, e chame "computar".
Isso difere significativamente dos outros exemplos aqui: a classe é instável (ao contrário de uma classe de utilitário), mas as instâncias são privadas (ao contrário dos métodos de fábrica, incluindo singletons etc.) e podem viver na pilha, pois nunca escapam.
Esse padrão é muito útil no POO de baixo para cima, onde objetos são usados para simplificar a implementação de baixo nível, mas não necessariamente são expostos externamente, e contrasta com o OOP de cima para baixo que geralmente é apresentado e começa com interfaces de alto nível.
Às vezes, é útil se você deseja controlar como e quando (e quantas) as instâncias de um objeto são criadas.
Entre outros, usados em padrões:
Singleton pattern
Builder pattern
O uso de construtores privados também pode ser aumentar a legibilidade / manutenção em face do design controlado por domínio. Em "Microsoft .NET - Aplicativos de arquitetura para empresas, 2ª edição":
var request = new OrderRequest(1234);
Cite: "Existem dois problemas aqui. Primeiro, ao analisar o código, dificilmente se pode adivinhar o que está acontecendo. Uma instância do OrderRequest está sendo criada, mas por que e usando quais dados? O que é 1234? Isso leva ao segundo problema: você está violando o idioma onipresente do contexto limitado.O idioma provavelmente diz algo assim: um cliente pode emitir uma solicitação de pedido e pode especificar um ID de compra.Se esse for o caso, aqui está uma maneira melhor de obter uma nova instância OrderRequest : "
var request = OrderRequest.CreateForCustomer(1234);
Onde
private OrderRequest() { ... }
public OrderRequest CreateForCustomer (int customerId)
{
var request = new OrderRequest();
...
return request;
}
Não estou defendendo isso para todas as classes, mas para o cenário DDD acima, acho que faz todo sentido evitar a criação direta de um novo objeto.