Jawaban:
Beberapa alasan di mana Anda mungkin memerlukan konstruktor pribadi:
final
level kelas. Menempatkan konstruktor pribadi tidak berguna karena alasan ini.
final
. Inilah yang Sun lakukan untuk kelas String, dan potongan yang wajar dari API yang seharusnya tidak diperpanjang.
Dengan menyediakan konstruktor pribadi Anda mencegah instance kelas dari diciptakan di tempat lain selain kelas ini. Ada beberapa kasus penggunaan untuk menyediakan konstruktor tersebut.
A. Instance kelas Anda dibuat dalam suatu static
metode. The static
Metode ini kemudian dinyatakan sebagai public
.
class MyClass()
{
private:
MyClass() { }
public:
static MyClass * CreateInstance() { return new MyClass(); }
};
B. Kelas Anda adalah singleton . Ini berarti, tidak lebih dari satu instance kelas Anda ada di program.
class MyClass()
{
private:
MyClass() { }
public:
MyClass & Instance()
{
static MyClass * aGlobalInst = new MyClass();
return *aGlobalInst;
}
};
C. (Hanya berlaku untuk standar C ++ 0x yang akan datang) Anda memiliki beberapa konstruktor. Beberapa dari mereka dinyatakan public
, yang lain private
. Untuk mengurangi ukuran kode, konstruktor publik 'memanggil' konstruktor pribadi yang pada gilirannya melakukan semua pekerjaan. public
Konstruktor Anda disebut konstruktor pendelegasian :
class MyClass
{
public:
MyClass() : MyClass(2010, 1, 1) { }
private:
MyClass(int theYear, int theMonth, int theDay) { /* do real work */ }
};
D. Anda ingin membatasi penyalinan objek (misalnya, karena menggunakan sumber daya bersama):
class MyClass
{
SharedResource * myResource;
private:
MyClass(const MyClass & theOriginal) { }
};
E. Kelas Anda adalah kelas utilitas . Itu artinya, hanya berisi static
anggota. Dalam hal ini, tidak ada instance objek yang harus dibuat dalam program.
Untuk meninggalkan "pintu belakang" yang memungkinkan kelas teman lain / fungsi untuk membangun objek dengan cara yang dilarang untuk pengguna. Contoh yang terlintas dalam pikiran adalah wadah yang membangun iterator (C ++):
Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
// and Container is a friend of Iterator.
friend
mana itu tidak dijamin - dan ada banyak kasus di mana itu adalah ide yang buruk. Sayangnya, pesan tersebut telah diterima dengan baik, dan banyak pengembang tidak pernah mempelajari bahasa dengan cukup baik untuk memahami bahwa penggunaan sesekali friend
tidak hanya dapat diterima, tetapi lebih disukai . Contoh Anda adalah kasus seperti itu. Kopling kuat yang disengaja bukanlah kejahatan, ini adalah keputusan desain.
Semua orang terjebak pada masalah Singleton, wow.
Hal-hal lain:
Ini bisa sangat berguna untuk konstruktor yang berisi kode umum; konstruktor pribadi dapat dipanggil oleh konstruktor lain, menggunakan 'this (...);' notasi. Dengan membuat kode inisialisasi umum dalam konstruktor pribadi (atau yang dilindungi), Anda juga membuat jelas secara eksplisit bahwa kode itu hanya dipanggil selama konstruksi, yang tidak demikian jika hanya berupa metode:
public class Point {
public Point() {
this(0,0); // call common constructor
}
private Point(int x,int y) {
m_x = x; m_y = y;
}
};
Ada beberapa contoh di mana Anda mungkin tidak ingin menggunakan konstruktor publik; misalnya jika Anda ingin kelas singleton.
Jika Anda menulis sebuah majelis yang digunakan oleh pihak ke-3 mungkin ada sejumlah kelas internal yang Anda hanya ingin dibuat oleh majelis Anda dan tidak akan dipakai oleh pengguna majelis Anda.
Ini memastikan bahwa Anda (kelas dengan konstruktor pribadi) mengontrol bagaimana konstruktor dipanggil.
Contoh: Metode pabrik statis di kelas dapat mengembalikan objek ketika metode pabrik memilih untuk mengalokasikannya (seperti pabrik tunggal misalnya).
Kita juga dapat memiliki konstruktor pribadi, untuk memulai pembuatan objek hanya dengan kelas tertentu (Untuk alasan keamanan).
Contoh 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.
}
};
Catatan: Catatan: Hanya ClientClass (karena itu adalah teman SecureClass) yang dapat memanggil Constructor SecureClass.
Berikut adalah beberapa penggunaan konstruktor pribadi:
Saya melihat pertanyaan dari Anda menangani masalah yang sama.
Sederhananya jika Anda tidak ingin orang lain membuat instance, maka pertahankan konstuktor dalam ruang lingkup terbatas. Aplikasi praktis (Contoh) adalah pola tunggal.
Anda seharusnya tidak menjadikan konstruktor sebagai pribadi. Titik. Buat itu terlindungi, sehingga Anda dapat memperpanjang kelas jika perlu.
Sunting: Saya mendukung itu, tidak peduli berapa banyak downvotes yang Anda lemparkan pada ini. Anda memotong potensi untuk pengembangan kode di masa mendatang. Jika pengguna atau pemrogram lain benar-benar bertekad untuk memperluas kelas, maka mereka hanya akan mengubah konstruktor menjadi dilindungi dalam sumber atau bytecode. Anda tidak akan mencapai apa pun selain untuk membuat hidup mereka sedikit lebih sulit. Sertakan peringatan dalam komentar konstruktor Anda, dan biarkan di situ.
Jika ini adalah kelas utilitas, solusi yang lebih sederhana, lebih benar, dan lebih elegan adalah menandai seluruh kelas "final statis" untuk mencegah ekstensi. Tidak ada gunanya hanya menandai konstruktor pribadi; pengguna yang benar-benar bertekad selalu dapat menggunakan refleksi untuk mendapatkan konstruktor.
protected
konstruktor yang baik adalah dengan memaksa penggunaan metode pabrik statis, yang memungkinkan Anda untuk membatasi instantiasi atau mengumpulkan & menggunakan kembali sumber daya yang mahal (koneksi DB, sumber daya asli).Konstruktor bersifat pribadi untuk beberapa tujuan seperti ketika Anda perlu mengimplementasikan singleton atau membatasi jumlah objek kelas. Misalnya dalam implementasi singleton kita harus menjadikan konstruktor sebagai pribadi
#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();
}
Sekali lagi jika Anda ingin membatasi pembuatan objek hingga 10 maka gunakan yang berikut ini
#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
}
Terima kasih
Anda dapat memiliki lebih dari satu konstruktor. C ++ menyediakan konstruktor default dan konstruktor salin default jika Anda tidak menyediakan secara eksplisit. Misalkan Anda memiliki kelas yang hanya dapat dibangun menggunakan beberapa konstruktor berparameter. Mungkin itu menginisialisasi variabel. Jika pengguna kemudian menggunakan kelas ini tanpa konstruktor itu, mereka dapat menyebabkan masalah tanpa akhir. Aturan umum yang baik: Jika implementasi default tidak valid, jadikan konstruktor default dan salin menjadi pribadi dan jangan berikan implementasi:
class C
{
public:
C(int x);
private:
C();
C(const C &);
};
Gunakan kompiler untuk mencegah pengguna menggunakan objek dengan konstruktor default yang tidak valid.
Mengutip dari Java Efektif , Anda dapat memiliki kelas dengan konstruktor pribadi untuk memiliki kelas utilitas yang mendefinisikan konstanta (sebagai bidang final statis).
( EDIT: Sesuai komentar, ini adalah sesuatu yang mungkin hanya dapat diterapkan dengan Java, saya tidak mengetahui apakah konstruk ini berlaku / diperlukan dalam bahasa OO lainnya (katakanlah C ++))
Contohnya seperti di bawah ini:
public class Constants {
private Contants():
public static final int ADDRESS_UNIT = 32;
...
}
EDIT_1 : Sekali lagi, penjelasan di bawah ini berlaku di Jawa: (dan merujuk dari buku, Java Efektif )
Instansiasi kelas utilitas seperti yang di bawah ini, meskipun tidak berbahaya, tidak melayani tujuan apa pun karena mereka tidak dirancang untuk dipakai.
Misalnya, katakanlah tidak ada Konstruktor pribadi untuk Konstanta kelas. Potongan kode seperti di bawah ini valid tetapi tidak lebih baik menyampaikan maksud pengguna kelas Konstanta
unit = (this.length)/new Constants().ADDRESS_UNIT;
berbeda dengan kode like
unit = (this.length)/Constants.ADDRESS_UNIT;
Juga saya pikir konstruktor pribadi menyampaikan maksud perancang kelas Constants (katakanlah) lebih baik.
Java menyediakan konstruktor publik tanpa parameter default jika tidak ada konstruktor yang disediakan, dan jika niat Anda adalah mencegah instantiasi maka konstruktor pribadi diperlukan.
Seseorang tidak dapat menandai kelas statis tingkat atas dan bahkan kelas akhir dapat dipakai.
Kelas utilitas dapat memiliki konstruktor pribadi. Pengguna kelas tidak boleh membuat instance kelas-kelas ini:
public final class UtilityClass {
private UtilityClass() {}
public static utilityMethod1() {
...
}
}
Salah satu penggunaan penting adalah di kelas 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
}
};
Ini juga cocok, Jika kelas Anda hanya memiliki metode statis. yaitu tidak ada yang perlu instantiate kelas Anda
Ini benar-benar satu alasan yang jelas: Anda ingin membangun objek, tetapi tidak praktis untuk melakukannya (dalam hal antarmuka) dalam konstruktor.
The Factory
contoh adalah cukup jelas, biarkan aku menunjukkan Named Constructor
idiom.
Katakanlah saya memiliki kelas Complex
yang dapat mewakili bilangan kompleks.
class Complex { public: Complex(double,double); .... };
Pertanyaannya adalah: apakah konstruktor mengharapkan bagian yang nyata dan imajiner, atau apakah ia mengharapkan norma dan sudut (koordinat kutub)?
Saya dapat mengubah antarmuka untuk membuatnya lebih mudah:
class Complex
{
public:
static Complex Regular(double, double = 0.0f);
static Complex Polar(double, double = 0.0f);
private:
Complex(double, double);
}; // class Complex
Ini disebut Named Constructor
idiom: kelas hanya dapat dibangun dari awal dengan secara eksplisit menyatakan konstruktor mana yang ingin kita gunakan.
Ini adalah kasus khusus dari banyak metode konstruksi. Pola Desain memberikan baik jumlah cara untuk membangun objek: Builder
, Factory
, Abstract Factory
, ... dan konstruktor pribadi akan memastikan bahwa pengguna benar dibatasi.
Selain kegunaan yang lebih dikenal ...
Untuk menerapkan pola Object Method , yang saya ringkas sebagai:
"Konstruktor pribadi, metode statis publik"
"Objek untuk implementasi, fungsi untuk antarmuka"
Jika Anda ingin menerapkan fungsi menggunakan objek, dan objek tidak berguna di luar melakukan perhitungan satu kali (dengan pemanggilan metode), maka Anda memiliki Objek Throwaway . Anda dapat merangkum pembuatan objek dan pemanggilan metode dalam metode statis, mencegah anti-pola umum ini:
z = new A(x,y).call();
... menggantinya dengan panggilan fungsi (namespaced):
z = A.f(x,y);
Penelepon tidak perlu tahu atau peduli bahwa Anda menggunakan objek secara internal, menghasilkan antarmuka yang lebih bersih, dan mencegah sampah dari objek berkeliaran atau penggunaan objek yang salah.
Misalnya, jika Anda ingin memecah perhitungan di seluruh metode foo
,, bar
dan zork
, misalnya untuk berbagi keadaan tanpa harus melewati banyak nilai masuk dan keluar dari fungsi, Anda bisa menerapkannya sebagai berikut:
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) { /* ... */ };
}
Metode ini Pola objek diberikan dalam Smalltalk Best Practice Patterns , Kent Beck, halaman 34-37, di mana ini adalah langkah terakhir dari pola refactoring, yang berakhir:
- Ganti metode asli dengan yang membuat instance kelas baru, dibangun dengan parameter dan penerima metode asli, dan memanggil "compute".
Ini berbeda secara signifikan dari contoh-contoh lain di sini: kelasnya instantiable (tidak seperti kelas utilitas), tetapi instansnya pribadi (tidak seperti metode pabrik, termasuk lajang dll.), Dan dapat hidup di stack, karena mereka tidak pernah keluar.
Pola ini sangat berguna dalam OOP dasar, di mana objek digunakan untuk menyederhanakan implementasi tingkat rendah, tetapi tidak perlu diekspos secara eksternal, dan kontras dengan OOP top-down yang sering disajikan dan dimulai dengan antarmuka tingkat tinggi.
Terkadang berguna jika Anda ingin mengontrol bagaimana dan kapan (dan berapa banyak) instance dari objek dibuat.
Antara lain, digunakan dalam pola:
Singleton pattern
Builder pattern
Penggunaan konstruktor pribadi juga bisa untuk meningkatkan keterbacaan / pemeliharaan dalam menghadapi desain berbasis domain. Dari "Microsoft .NET - Aplikasi Architecing untuk Perusahaan, Edisi ke-2":
var request = new OrderRequest(1234);
Mengutip, "Ada dua masalah di sini. Pertama, ketika melihat kode, orang hampir tidak bisa menebak apa yang terjadi. Contoh dari OrderRequest sedang dibuat, tetapi mengapa dan menggunakan data yang mana? Apa 1234? Ini mengarah ke masalah kedua: Anda melanggar bahasa di mana-mana dari konteks yang dibatasi. Bahasa ini mungkin mengatakan sesuatu seperti ini: pelanggan dapat mengeluarkan permintaan pesanan dan diizinkan untuk menentukan ID pembelian. Jika demikian, inilah cara yang lebih baik untuk mendapatkan contoh OrderRequest baru : "
var request = OrderRequest.CreateForCustomer(1234);
dimana
private OrderRequest() { ... }
public OrderRequest CreateForCustomer (int customerId)
{
var request = new OrderRequest();
...
return request;
}
Saya tidak menganjurkan ini untuk setiap kelas tunggal, tetapi untuk skenario DDD di atas saya pikir itu masuk akal untuk mencegah penciptaan langsung objek baru.