Contents
Singleton Principle (A class of which only a single instance can exist) termasuk dalam kategori Creational Pattern, yaitu pola atau teknik pemrograman mengenai metode dalam pembuatan object. Singleton pattern adalah design pattern yang digunakan untuk membatasi instanisasi dari suatu kelas menjadi hanya satu object, membatasi sebuah global point of access ke suatu object. Jika kita ingin membuat multiple instances dari kelas singleton, hasilnya akan percuma karena metode ini memaksa objek memiliki hanya satu instance singleton class client.
Kali ini, kita tidak hanya membahas apa itu singleton principle, tapi juga membahas kelemahan Design Pattern Singleton, dan perdebatan apakah singleton bukan design pattern dan bagaimana menerapkan thread optimized singleton.
Untuk Demo Singleton menggunakan Swing GUI berbasis java, download Link nya dengan klik link ini.
Konsep Singleton Design Pattern
Singleton Pattern pada dasarnya masih dalam kategori Creational design pattern yang memungkinkanmu memiliki kelas yang hanya memiliki satu instance dan hanya menyediakan satu titik akses global ke instance ini. Kamu dapat perhatikan gambar berikut:

Katakanlah kamu membuat aplikasi dan kamu ingin membuat global state dimana akan mempertahankan statenya ke seluruh lifecycle aplikasi. Satu-satunya cara adalah kamu hanya menyediakan satu jalur untuk mereferensi dan mengakses global state (satu instance diseluruh aplikasi). karena jika ada dua “jalur” akan ada perbedaan output tentunya.
Misal kamu ingin sebuah Arraylist dapat diakses secara global dengan value array yang akan selalu sama ketika dipanggil di semua tempat. Dan kamu ingin ketika memodifikasi arraylist atau list seperti menambahkan atau mengurangi isi array di satu tempat misal kelas A, maka semua kelas tempat arraylist dipanggil akan mempunyai nilai arraylist yang sama persis seperti di kelas A.
Bentuk visual dari diagram model singleton principle menggunakan UML

Kalian perhatikan keunikan dari UML Singleton diatas, constructor dari singleton dibuat private, mengapa demikian? Ide memprivate constructor adalah agar ketika client memanggil kelas singleton, dalam UML Case ini SingleGlobalClass, client tidak boleh memanggil konstruktor sehingga client tidak membuat banyak instance dikelas singleton. Dan selanjutnya getInstance method bekerja dengan cara melakukan pengecekan, jika sudah ada instance objek kelas singleton maka jangan buat instance, namun jika belum ada buat instance.
class Singleton {
private static Singleton instance = null;
// konstruktor yang modifiernya private
private Singleton {
}
public static Singleton GetInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}Kelas singleton memiliki konstruktor yang hak aksesnya adalah private. Sehingga konstruktor hanya dapat dipanggil dari dalam kelas. Tujuan untuk mencegah constructor , di akses dengan keyword new pada class lain.
Objek lain yang membutuhkan kelas ini dapat meminta instance kelas dengan memanggil method statik GetInstance.
Deklarasi null bertujuan bila belum ada instance maka akan membuat instance class yang baru.
Metode getInstance digunakan juga untuk memberikan akses dari luar ke objek dan dapat digunakan dengan cara berikut:
Singleton.getInstance().doSomething();
Cara Menggunakan: Langkah-langkah implementasi Singleton Sederhana
- Membuat constractor pada kelas yang akan digunakan sebagai singleton objek. Pada constractor ini akan dilakukan instansiasi objek setelah dilakukan pengecekan apakah objek telah dibuat atau belum. Sehingga ketika objek telah dibuat, maka tidak akan dibuat baru lagi.
- Membuat private static field untuk menyimpan objek yang telah dibuat pada constractor.
- Membuat Public Method yang digunakan sebagai pemanggilan objek ini. Sehingga ketika ada yang membutuhkan objek ini, tinggal memanggil method ini, tanpa harus membuat instansiasi baru. (contoh method : getInstance()).
Penerapan Design Pattern Singleton di dunia nyata
Secara definisi, Singleton digunakan apabila menemukan masalah desain, di mana kita hanya perlu memiliki satu instance dari jenis kelas tertentu di seluruh domain aplikasi. Misalnya untuk kasus-kasus berikut :
File log aplikasi
Singleton pattern digunakan dalam desain class logger. Class ini umumnya diimplementasikan sebagai singleton, dan menyediakan global logging access point dalam semua komponen aplikasi tanpa perlu untuk menciptakan sebuah objek setiap kali operasi logging dilakukan.
Konfigurasi aplikasi
Pola Singleton digunakan untuk merancang kelas yang menyediakan pengaturan konfigurasi untuk aplikasi. Menerapkan kelas konfigurasi sebagai Singleton tidak hanya menyediakan titik akses global, tetapi juga menggunakan instance sebagai “cache” untuk objek.
Contoh Program Singleton menggunakan Java GUI (Java Swing Framework)
Studi Kasus Singleton Principle
Bagaimana agar ketika memanipulasi satu “data”, data tersebut sama di semua kelas atau dapat diakses secara global. Nilai data tersebut apabila dimanipulasi di satu instansi maka nilainya akan berubah secara global.
Logic dari kasus tersebut :
Dibuat kelas singleton, yang berisi data tersebut, di sini anggap saja data tersebut berupa String.
Di sini kelas Singleton akan mereferensikan kelasnya sendiri kemudian memastikan dan membatasi instance class hanya satu, atau dengan kata lain tidak boleh ada dua object untuk class tersebut. Karena itu ketika singleton dipanggil diluar kelas menjadi banyak objek, nilai dari String yang dikelola tetaplah sama, apabila diakses dengan titik point method global yaitu getInstance.
Boiler Kode Program Singleton menggunakan Swing GUI
SingletonClassExample
public class SingletonClassExample {
// single_instance variabel statis tipe Singleton
private static SingletonClassExample single_instance = null;
// variabel tipe String
public String myText;
// konstruktor pribadi terbatas pada kelas ini sendiri (tidak ada kelas lain yang dapat mengakses)
private SingletonClassExample()
{
myText = "Hallo saya String punya kelas singleton";
}
// metode statis untuk membuat instance dari kelas Singleton
public static SingletonClassExample getInstance()
{
if (single_instance == null)
single_instance = new SingletonClassExample();
return single_instance;
}
}
Di sini data String myText tidak bisa dimanipulasi kecuali oleh kelas singleton, karena aksesnya berada dalam konstruktor dengan akses private. getInstance() bertanggung jawab untuk membuat instance unik dari kelasnya jika belum dibuat dan mengembalikan instance tersebut.
Menampilkan hasil string pada setiap instance pada kelas ListInstancesFrame
public class ListInstacesFrame extends javax.swing.JFrame {
/**
* Creates new form FirstFrame
*/
public ListInstacesFrame() {
initComponents();
createList();
}
private void createList(){
// instantiating Singleton class with variable x
SingletonClassExample x = SingletonClassExample.getInstance();
// instantiating Singleton class with variable y
SingletonClassExample y = SingletonClassExample.getInstance();
// instantiating Singleton class with variable z
SingletonClassExample z = SingletonClassExample.getInstance();
DefaultListModel<String> StringList = new DefaultListModel<>();
StringList.addElement("String dari x is " + x.myText);
StringList.addElement("String dari y is " + y.myText);
StringList.addElement("String dari z is " + z.myText);
jList1.setModel(StringList);
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
// TODO add your handling code here:
new ManipulateStringFrame().setVisible(true);;
dispose();
}//GEN-LAST:event_jButton1ActionPerformed
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ListInstacesFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jButton1;
private javax.swing.JList<String> jList1;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration//GEN-END:variables
}
Di sini terdapat tiga objek singleton yang berbeda yang disimpan dalam method createList(). Kemudian variable string myText pada tiga objek singleton tersebut dipanggil dan dimasukkan dalam jList1 agar dapat tampil dalam frame.

EventHandler Button jButton1ActionPerformed ketika diklik akan menuju ke frame manipulasi String dan mendispose frame dari ListInstancesFrame.
Boiler Kode ManipulateStringFrame
public class ManipulateStringFrame extends javax.swing.JFrame {
/**
* Creates new form ManipulateInstaceFrame
*/
public ManipulateStringFrame() {
initComponents();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
// TODO add your handling code here:
SingletonClassExample a = SingletonClassExample.getInstance();
a.myText = (a.myText).toUpperCase();
new ListInstacesFrame().setVisible(true);
dispose();
}//GEN-LAST:event_jButton1ActionPerformed
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
SingletonClassExample b = SingletonClassExample.getInstance();
b.myText = (b.myText).toLowerCase();
new ListInstacesFrame().setVisible(true);
dispose();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ManipulateStringFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
// End of variables declaration//GEN-END:variables
}
Untuk pembuktian bahwa Singleton memberi data global, dibuat dua objek singleton lagi yang berbeda. Satu di dalam method jButton1ActionPerformed dan satu di jButton2ActionPerformed. Kemudian String yang ada pada tiap objek singleton dimanipulasi.
Demo Program Swing GUI

Ketika kita menekan tombol manipulasi String, maka akan muncul jendela baru berikut

Hasil String saat di upper case

Hasil String saat di lower case

Di sini dapat dilihat nilai String setiap instance singleton sama, baik sebelum dimanipulasi dan sesudah dimanipulasi.
Masalah pada Singleton dan Mengapa Singleton Design Pattern adalah anti pattern
Ada perdebatan singleton bukan design pattern, bahkan singleton dianggap antipattern, alasannya karena kelas singleton melanggar prinsip single responsibility prinsiple yaitu selain menghandle life cycle atau state dari kelasnya, kalau kalian melihat ThreadOptimizedSingleton, kelas ini juga menghandle beberapa variable yaitu variable value. Tetapi, kenapa banyak framework yang menggunakan Singleton seperti Spring Core, Dagger? Dan untuk life cycle bisa didebat bahwa secara naluri, singleton hanya membuat kelasnya menjadi “stateless”.
Singleton juga menjadi permasalahan pada aplikasi multithreading. Tentu ada cara untuk mengakali kasus multithreading ini, namun sering kali membuat sebuah kode yang kompleks untuk suatu kasus yang sederhana (which sering kali menjadi jurus debat oleh developer yang anti dengan singleton design pattern).
Perbaikan Penerapan Kode Design Pattern Singleton yang Efisien
Ada banyak cara untuk implementasi singleton, hanya tinggal konsep singleton terbaik apa yang kamu ingin terapkan. Singleton sendiri sangat rentan dalam multithreading, karena akan ada kemungkinan lebih dari satu thread mengakses satu instance sehingga menyebabkan lebih dari satu instance singleton dibuat. Solusi singleton agar dapat berjalan di multithread adalah menggunakan enumeration. Sekarang kita akan membuat singleton dengan optimisasi multi thread
Enum Singleton
enum class MyEnumSingleton {
INSTANCE;
var value = 0
}Kelas Client
class Client {
companion object{
@JvmStatic
fun main(args: Array<String>) {
val singleton = MyEnumSingleton.INSTANCE
singleton.value = 4
println(singleton.value)
val singleton2 = MyEnumSingleton.INSTANCE
println(singleton2.value)
singleton.value = 8
println(singleton.value)
println(singleton2.value)
}
}
}
Berbeda dengan objek pada umumnya, inisialisasi enum dilakukan di JVMnya sehingga tidak akan ada inisialisasi tambahan yang dilakukan oleh pemanggilan thread sehingga hanya akan ada satu instance saja. Permasalahan dari singleton enumeration adalah kamu akan kehilangan semua data kalau kamu melakukan deinisialisasi objek. Selain menggunakan enum, kamu bisa menggunakan static deklarator sebagai alternatif optimisasi singleton untuk multi thread.
Selain itu, kamu juga bisa membuat thread safe singleton dengan contoh kotlin seperti berikut
class ThreadOptimizedSingleton {
var value = 0
companion object{
@Volatile
private var instance: ThreadOptimizedSingleton? = null
}
fun getInstance(): ThreadOptimizedSingleton? {
if (instance != null) return instance
synchronized(ThreadOptimizedSingleton::class.java) {
if (instance == null) {
instance = ThreadOptimizedSingleton()
}
}
return instance
}
}Terkadang, thread pertama yang mengakses singleton sedang berada pada task pengecekan apakah instance tersedia atau tidak, kemudian karena instance masih null maka thread pertama tersebut akan membuat instance, namun tiba-tiba thread pertama melakukan sleep sehingga pembuatan instance terhenti sementara.
Di saat bersamaan thread kedua melakukan cek instance, karena thread pertama belum sempat membuat instance, maka thread kedua lanjut membuat instance.
Saat thread pertama bangun, ia tidak akan mengecek kembali apakah instance singleton masih null atau sudah ada, namun langsung membuat instance singleton. Sehingga akan ada problem muncul: dua global objek class singleton.
Dengan menggunakan kotlin thread optimized singleton example di atas, akan dilakukan lock multithread menggunakan synchronized pada variable instance sehingga hanya ada satu thread saja yang mengakses instance. Kemudian volatile digunakan agar thread melakukan pengecekan lebih dari sekali untuk variable instance.
val threadOptimizedSingleton = ThreadOptimizedSingleton().getInstance()
threadOptimizedSingleton!!.value = 6
val threadOptimizedSingleton2 = ThreadOptimizedSingleton().getInstance()
println("\nthe threadoptimized value = ${threadOptimizedSingleton.value}")
println("\nthe threadoptimized value = ${threadOptimizedSingleton2!!.value}")
Kesimpulan
Pola Singleton membatasi instantiation kelas dan memastikan bahwa hanya satu instance kelas ada di mesin virtual.
Kelas singleton harus menyediakan titik akses global untuk mendapatkan instance kelas.
Melalui definisi dan implementasi di atas, pola singleton cocok untuk logging, caching dan berbagi resources.
Terima kasih sudah berkunjung di Nako Info Tekno, untuk tutorial software arsitektur silahkan kunjungi link ini.
Join our list
Subscribe to our mailing list and get interesting stuff and updates to your email inbox.



0 Comments