Singleton di Jawa

1. Pengenalan

Dalam artikel ringkas ini, kita akan membincangkan dua cara paling popular dalam menerapkan Singleton di Jawa biasa.

2. Singleton Berasaskan Kelas

Pendekatan yang paling popular adalah dengan menerapkan Singleton dengan membuat kelas biasa dan memastikannya:

  • Pembina peribadi
  • Medan statik yang mengandungi satu-satunya contohnya
  • Kaedah kilang statik untuk mendapatkan contoh

Kami juga akan menambahkan harta maklumat, untuk penggunaan kemudian sahaja. Oleh itu, pelaksanaan kami akan kelihatan seperti ini:

public final class ClassSingleton { private static ClassSingleton INSTANCE; private String info = "Initial info class"; private ClassSingleton() { } public static ClassSingleton getInstance() { if(INSTANCE == null) { INSTANCE = new ClassSingleton(); } return INSTANCE; } // getters and setters }

Walaupun ini adalah pendekatan yang biasa, perlu diketahui bahawa ia boleh menjadi masalah dalam senario multithreading , yang merupakan sebab utama untuk menggunakan Singleton.

Ringkasnya, ini dapat menghasilkan lebih dari satu contoh, melanggar prinsip inti corak. Walaupun ada penyelesaian mengunci untuk masalah ini, pendekatan kami seterusnya menyelesaikan masalah ini pada peringkat awal.

3. Enum Singleton

Melangkah ke hadapan, jangan bincangkan pendekatan lain yang menarik - iaitu menggunakan penghitungan:

public enum EnumSingleton { INSTANCE("Initial class info"); private String info; private EnumSingleton(String info) { this.info = info; } public EnumSingleton getInstance() { return INSTANCE; } // getters and setters }

Pendekatan ini mempunyai siri dan keselamatan benang yang dijamin oleh pelaksanaan enum itu sendiri, yang memastikan secara dalaman bahawa hanya satu contoh yang ada, memperbaiki masalah yang ditunjukkan dalam pelaksanaan berdasarkan kelas.

4. Penggunaan

Untuk menggunakan ClassSingleton kami , kami hanya perlu mendapatkan contohnya secara statik:

ClassSingleton classSingleton1 = ClassSingleton.getInstance(); System.out.println(classSingleton1.getInfo()); //Initial class info ClassSingleton classSingleton2 = ClassSingleton.getInstance(); classSingleton2.setInfo("New class info"); System.out.println(classSingleton1.getInfo()); //New class info System.out.println(classSingleton2.getInfo()); //New class info

Adapun EnumSingleton , kita dapat menggunakannya seperti Java Enum yang lain:

EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE.getInstance(); System.out.println(enumSingleton1.getInfo()); //Initial enum info EnumSingleton enumSingleton2 = EnumSingleton.INSTANCE.getInstance(); enumSingleton2.setInfo("New enum info"); System.out.println(enumSingleton1.getInfo()); // New enum info System.out.println(enumSingleton2.getInfo()); // New enum info

5. Perangkap Umum

Singleton adalah corak reka bentuk yang mudah menipu, dan ada beberapa kesalahan umum yang mungkin dilakukan oleh pengaturcara ketika membuat singleton.

Kami membezakan dua jenis masalah dengan single:

  • wujud (adakah kita memerlukan singleton?)
  • implementasi (adakah kita melaksanakannya dengan betul?)

5.1. Isu Eksistensial

Secara konseptual, singleton adalah sejenis pemboleh ubah global. Secara umum, kita tahu bahawa pemboleh ubah global harus dielakkan - terutama jika keadaannya berubah-ubah.

Kami tidak mengatakan bahawa kami tidak boleh menggunakan single. Walau bagaimanapun, kami mengatakan bahawa mungkin ada cara yang lebih cekap untuk mengatur kod kami.

Sekiranya pelaksanaan suatu metode bergantung pada objek tunggal, mengapa tidak meneruskannya sebagai parameter? Dalam kes ini, kami secara jelas menunjukkan kaedah bergantung. Akibatnya, kita mungkin dengan mudah mengejek kebergantungan ini (jika perlu) ketika melakukan ujian.

Sebagai contoh, singleton sering digunakan untuk merangkumi data konfigurasi aplikasi (iaitu, sambungan ke repositori). Sekiranya ia digunakan sebagai objek global, menjadi sukar untuk memilih konfigurasi untuk persekitaran ujian.

Oleh itu, semasa kami menjalankan ujian, pangkalan data pengeluaran akan dimanjakan dengan data ujian, yang sukar diterima.

Sekiranya kita memerlukan singleton, kita mungkin mempertimbangkan kemungkinan mendelegasikan instansiasi ke kelas lain - semacam kilang - yang harus memastikan untuk memastikan bahawa hanya ada satu contoh singleton yang sedang bermain.

5.2. Isu Pelaksanaan

Walaupun single kelihatan sederhana, pelaksanaannya mungkin mengalami pelbagai masalah. Semua menghasilkan kenyataan bahawa kita mungkin mempunyai lebih daripada satu contoh kelas.

Penyegerakan

Pelaksanaan dengan konstruktor persendirian yang kami tunjukkan di atas tidak selamat dari benang: ia berfungsi dengan baik dalam persekitaran utas tunggal, tetapi dalam rangkaian multi-utas, kita harus menggunakan teknik penyegerakan untuk menjamin keberanian operasi:

public synchronized static ClassSingleton getInstance() { if (INSTANCE == null) { INSTANCE = new ClassSingleton(); } return INSTANCE; }

Perhatikan kata kunci yang diselaraskan dalam deklarasi kaedah. Badan kaedah mempunyai beberapa operasi (perbandingan, instansiasi, dan pengembalian).

Sekiranya tidak diselaraskan, ada kemungkinan dua utas mengganggu pelaksanaannya sedemikian rupa sehingga ungkapan INSTANCE == null dinilai benar untuk kedua-dua utas dan, sebagai hasilnya, dua kejadian ClassSingleton dibuat.

Penyegerakan mungkin mempengaruhi prestasi dengan ketara. Sekiranya kod ini sering dipanggil, kita harus mempercepatnya dengan menggunakan pelbagai teknik seperti inisialisasi malas atau penguncian sekali ganda (ketahuilah bahawa ini mungkin tidak berfungsi seperti yang diharapkan kerana pengoptimuman penyusun). Kami dapat melihat lebih banyak perincian dalam tutorial kami "Double-Checked Locking with Singleton".

Pelbagai Contoh

Terdapat beberapa masalah lain dengan singleton yang berkaitan dengan JVM itu sendiri yang boleh menyebabkan kita berakhir dengan banyak kejadian single. Masalah-masalah ini agak halus, dan kami akan memberikan penerangan ringkas untuk masing-masing:

  1. Singleton semestinya unik bagi setiap JVM. Ini mungkin menjadi masalah bagi sistem atau sistem yang diedarkan yang dalamannya didasarkan pada teknologi yang diedarkan.
  2. Setiap pemuat kelas mungkin memuat versi singletonnya.
  3. Orang bujang mungkin dikumpulkan sampah setelah tidak ada orang yang merujuknya. Masalah ini tidak membawa kepada adanya beberapa contoh tunggal sekaligus, tetapi ketika dibuat ulang, contohnya mungkin berbeza dari versi sebelumnya.

6. Kesimpulannya

Dalam tutorial ringkas ini, kami memfokuskan pada bagaimana menerapkan pola Singleton hanya menggunakan inti Java, dan bagaimana memastikannya konsisten dan bagaimana memanfaatkan implementasi ini.

Pelaksanaan penuh contoh-contoh ini boleh didapati di GitHub.