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:

Singleton Design Pattern Concept, learning Design Pattern of Singleton

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

Singleton Design Pattern UML, Diagram example of Singleton Principle
Singleton 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

  1. 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.
  2. Membuat private static field untuk menyimpan objek yang telah dibuat pada constractor.
  3. 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.

Java GUI Demo of Singleton Implementation Example

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

Java GUI demo String Manipulation Globally using Singleton

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

Java GUI Design Pattern Singleton Principle

Hasil String saat di upper case

Java GUI Design Pattern Singleton

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)
        }
    }
}
Singleton Thread Optimized Demo

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}")
Thread Optimized Singleton Example using Kotlin

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.

Thank you for subscribing.

Something went wrong.


Like it? Share with your friends!

What's Your Reaction?

Unfortunate
0
Unfortunate
Meh
2
Meh
Wahaha
0
Wahaha
Nin nin
0
Nin nin
nakomin

Believe at the heart of BNRS

Here you will find content about developers needs whether it’s coding tutorials or the lifestyle of employee in the IT circle, understanding of the realm of ui/ux and futuristic tech for free in one place. Don’t forget to follow the nakotek socials to give the author enthusiasm in pioneering this website. #wahahaforever

0 Comments

Your email address will not be published. Required fields are marked *