Promo Lebaran, Kelas Online CODEPOLITAN Cukup Bayar Setengah Harga KLAIM PROMO
Lebih terarah belajar coding melalui Kelas Online dan Interactive Coding Lihat Materi Belajar

Mengenal dan Belajar Design Pattern Singleton

Ditulis oleh Ahmad Oriza, dipublikasi pada 10 Apr 2020 dalam kategori Tutorial
Mengenal dan Belajar Design Pattern Singleton - CodePolitan.com

Selamat datang kembali pada pembahasan design pattern. Semoga kamu semakin semangat belajar materi ini. Kali ini kita akan belajar pattern Singleton. Pattern ini banyak diterapkan di berbagai framework, salah satunya adalah CodeIgniter3. Sebenarnya masalah yang ingin diselesaikan oleh pattern ini adalah instansiasi.

Mungkin secara sadar ataupun tidak sadar kita sering menginstansiasi object yang sama di berbagai tempat atau file. Ternyata ini akan menyebabkan alokasi memory yang berlebihan. Jika satu atau dua objek mungkin tidak terasa, bagaimana jika banyak?

Nah, disini Singleton pattern mencoba untuk menyelesaikan masalah tersebut. Pola penerapan Singleton sangat dikomendasikan untuk class/object yang hanya diperlukan satu kali objek dalam runtime/eksekusi program kita. Contohnya apa? koneksi database, logging, dst.

Yang perlu dicatat tidak semua objek atau class harus menerapkan Singleton. Dalam praktiknya namanya memprogram OOP kita pasti membutuhkan banyak instansiasi objek.

Supaya lebih paham mari kita lihat kode berikut ini :

<?php

// Tanpa menggunakan prinsip singleton.
class Database {
    public function __construct()
    {
        // Misal disini kode koneksi ke database.
        // Kalau di PHP misalnya saja mysqli_connect atau PDO connection.
    }

    public function query($sql)
    {
        // Disini harusnya adalah sintaks PHP untuk melakukan query baik dengan mysqli_query atau PDO
        echo "Mengeksekusi \"{$sql}\" ..<br/>";
    }
}

// Menginstansiasi database.
$db = new Database;

// Melakukan query.
$db->query("SELECT * FROM users");
?>

Pada kode tersebut kita membuat class Database, tidak ada yang spesial. Method __contruct bertugas mengkoneksikan program kita dengan DBMS. Sedangkan method query bertugas menjalankan sintaks SQL. Disitu hanya contoh, hanya mencetak string saja. Selanjutnya database kita instansiasi dan melakukan query.

Output kode tersebut adalah :

Mengeksekusi "SELECT * FROM users" ..

Kode tersebut berjalan normal dan tidak ada masalah. Namun coba pikirkan jika program semakin kompleks, kamu harus meng-include kan file Database dimana-mana, pokoknya di semua lini kode yang membutuhkan koneksi database. Dalam satu kali runtime kamu tidak sadar beberapa kali menginstansiasi objek database, bukan hanya database, tapi juga objek lainnya yang sebenarnya hanya dibutuhkan satu kali instansiasi saja. Hal ini dapat menyebabkan kode kamu menjadi tidak efisien dan membuang-buang alokasi memory.

Ilustrasi Chaos :

// Menginstansiasi database di file A
$db = new Database;

// Menginstansiasi database di file B
$db = new Database;

// Menginstansiasi database di file C
$db = new Database;

Bahkan di file yang sama ada beberapa instansiasi :)

Lalu bagaimana pattern Singleton untuk menyelesaikan masalah ini? Oke, saatnya kita rombak ke Singleton. Mari kita lihat kode berikut ini :

<?php

// Sudah menggunakan prinsip singleton.
class Database {

    // Bikin wadah untuk menampung objek.
    private static $instance = null;

    public function __construct()
    {
        // Misal disini kode koneksi ke database.
        // Kalau di PHP misalnya saja mysqli_connect atau PDO connection.
    }

    // Ini method pamungkas buat bikin objek, tidak perlu pakai new lagi.
    public static function getInstance()
    {
        // Self sama kegunaanya dengan $this, tapi khusus untuk static property.
        // Disini kita cek apakah sebelumnya instance sudah bikin apa belum untuk cegah double.
        // Kalau belum pernah dibikin kita new! kalau sudah kembalikan yang sudah ada.
        if (self::$instance == null) {
            self::$instance = new Database();
        } 

        // Kembalikan.
        return self::$instance;
    }

    // Method seperti biasanya.
    public function query($sql)
    {
        echo "Mengeksekusi \"{$sql}\" ..<br/>";
    }
}

// Menginstansiasi database, via getInstance, tidak new lagi.
$db = Database::getInstance();

// Melakukan query.
$db->query("SELECT * FROM users");
?>

Outputnya sama saja :

Mengeksekusi "SELECT * FROM users" ..

Tapi cara kerjanya sudah beda jauh. Nah, bisa dilihat pada kode, cuma ada penambahan property private untuk menyimpan hasil instansiasi. Juga method getInstance untuk melakukan instansasi dengan tambahan pengecekan. Pada kode tersebut ketika kita butuh objek Database, dapat dipanggil dengan cara :

// Tidak menggunakan $db = new Database;
$db = Database::getInstance();

Dengan begini kita tidak akan pernah membuat instansiasi baru walaupun kode class ini di include dimana mana. Sudah pasti dalam runtime hanya akan menggunakan satu objek saja (satu alokasi memory). Kenapa bisa begini?

Cobalah disimak lagi kode berikut ini :

// Sudah ada belum?
if (self::$instance == null) {
    // Kalau blm ada bikin objek baru lalu assign ke property instance.
    self::$instance = new Database();
} 

// Kalau sudah ada kembalikan, tidak usah buat `new Database` lagi.
return self::$instance;

Pengecekan pada method getInstance() akan menghindari double objek. Dia mengecek badan property pada class Database. Menarik bukan?

Lanjut, kita simulasi panggil beberapa kali dalam satu file, coba modifikasi kode jadi seperti ini :

// Kode sebelumnya
...

// Walaupun berkali kali dipanggil tidak akan pernah membuat alokasi memory baru.
$db1 = Database::getInstance();
$db2 = Database::getInstance();
$db3 = Database::getInstance();
$db4 = Database::getInstance();

// Mengecek dan buktikan apakah sama?
if ($db1 === $db2) {
    // Kalau tercetak sama, berarti proven.
    echo '<br/>Sama!<br/>';
}

// Melakukan query.
$db1->query("SELECT * FROM users");
$db2->query("SELECT * FROM users");
$db3->query("SELECT * FROM users");
$db4->query("SELECT * FROM users");

Objek db1 sampai 4 pada kode diatas tidak akan pernah membuat objek baru. Dia akan memanggil objek yang sudah dibuat sebelumnya. Lalu disitu kita juga membuat kode perbandingan dengan === untuk memastikan objek tersebut sama saja.

Outputnya :

Sama!
Mengeksekusi "SELECT * FROM users" ..
Mengeksekusi "SELECT * FROM users" ..
Mengeksekusi "SELECT * FROM users" ..
Mengeksekusi "SELECT * FROM users" ..

Begitulah kira-kira penggunaan dari pattern Singleton. Silahkan coba praktekkan lagi. Coba asah lagi kemampuan pattern Singleton pada materi diluar Codepolitan. Bisa mencari kata kunci Singleton Pattern pada Google.

Sebagai informasi tambahan, pattern ini sebenarnya masih banyak diperdebatkan oleh berbagai pihak. Banyak orang yang tidak merekomendasikan pattern ini karena sulit untuk melakukan unit test pada program.

Namun nyatanya masih banyak yang menerapkan. Semua kembali ke kamu, lihat kondisi, jika bermanfaat pada studi kasus kamu, maka pakailah.

Referensi :
https://refactoring.guru/design-patterns/singleton
https://phpenthusiast.com/blog/the-singleton-design-pattern-in-php


background

Gabung CodePolitan Membership

Ingin belajar coding secara online dengan lebih terarah? Gabung sekarang dalam program Premium Membership di CodePolitan. Dapatkan ratusan modul belajar pemrograman premium dalam beragam format dengan materi silabus lengkap dan tersusun rapi dari awal hingga mahir.

LIHAT MATERI BELAJAR GABUNG MEMBERSHIP