Jelajahi pola desain Singleton: kapan menggunakannya, contoh TypeScript praktis, dan alternatif penting.
January 19, 2026 (3mo ago)
Menguasai pola desain Singleton: Panduan Lengkap untuk Pengembang
Jelajahi pola desain Singleton: kapan menggunakannya, contoh TypeScript praktis, dan alternatif penting.
← Back to blog
Mastering the Singleton Pattern in TypeScript: A Complete Guide

Dalam dunia pengembangan perangkat lunak, beberapa alat sangat kuat tetapi harus ditangani dengan hati-hati. Pola Singleton adalah salah satunya. Pada intinya, ini adalah konsep sederhana: memastikan sebuah kelas hanya memiliki satu instance dan menyediakan satu cara global untuk mengaksesnya.1
Bayangkan seperti pengelola konfigurasi pusat atau layanan logging khusus untuk seluruh aplikasi Anda. Anda tidak ingin ada beberapa objek konfigurasi yang saling bertentangan beredar, atau Anda tidak ingin entri log tersebar di berbagai file oleh instance logger yang saling bersaing. Singleton menghadirkan keteraturan dengan mencegah duplikasi ini, menghemat memori dan menghindari kekacauan. Ini adalah pola dasar untuk mengelola akses ke sumber daya bersama.
What Is The Singleton Pattern And When Is It Useful?
Bayangkan sebuah kerajaan abad pertengahan dengan hanya satu Juru Tulis Kerajaan resmi. Orang ini adalah satu-satunya yang berwenang untuk mencatat dekrit kerajaan. Ini memastikan setiap undang-undang dan pengumuman konsisten, benar-benar berwenang, dan disimpan dalam satu ledger yang definitif. Jika siapa pun bisa memutuskan menjadi juru tulis, kerajaan akan segera kacau dengan catatan yang saling bertentangan dan kebingungan massal.
Pola desain Singleton beroperasi berdasarkan prinsip yang sama dalam perangkat lunak Anda. Tugas utamanya adalah membatasi sebuah kelas sehingga hanya satu objek yang pernah bisa dibuat darinya. Satu-satunya instance ini menjadi sumber kebenaran untuk tugas tertentu, dan mudah diakses dari mana saja dalam basis kode Anda. Inilah cara Anda menegakkan kontrol atas sumber daya yang tidak boleh diduplikasi.
Core Purpose and Analogy
Singleton bukan hanya tentang mencegah pembuatan objek baru; ini tentang memusatkan kontrol. Sama seperti Juru Tulis Kerajaan menyediakan satu titik akses ke catatan resmi kerajaan, sebuah instance Singleton menawarkan gerbang yang tersedia secara universal ke sumber daya bersama. Ia menghentikan bagian-bagian aplikasi Anda membuat versi terisolasi dan berpotensi bertentangan.
Koneksi pool basis data adalah contoh klasik. Anda tentu tidak ingin setiap komponen di aplikasi Anda membuka koneksi terpisah ke basis data—itu cara pasti menguras sumber daya server dan membuat performa melambat. Sebagai gantinya, sebuah Singleton dapat mengelola satu pool koneksi, membagikannya secara efisien sesuai kebutuhan.
The core idea is simple yet powerful: one class, one instance, one global access point. This structure guarantees that all interactions with a specific resource go through a single, controlled channel.
Singleton Pattern At a Glance
| Characteristic | Description & Rationale |
|---|---|
| Single Instance | The class is designed to have only one instance throughout the application's lifecycle, often enforced with a private constructor. |
| Global Access Point | A static method (e.g., getInstance()) provides a single, well-known way to access the instance from anywhere in the code. |
| Lazy Initialization | The single instance is often created the first time it's requested, not at application startup, which can improve performance. |
| State Management | It acts as a centralized location for a specific piece of global state, like application settings or a user session. |
Tabel ini merangkum mengapa pola ini ada: untuk menegakkan satu instance yang dapat diakses secara global untuk sumber daya yang secara inheren bersifat tunggal.
Practical Use Cases
Meskipun pola Singleton memiliki kritik, pola ini bukan tanpa kegunaan yang sah. Ini paling efektif ketika Anda memiliki sumber daya yang, menurut sifatnya, unik dalam sistem.
Berikut beberapa skenario dimana Singleton masuk akal:
- Layanan logging: satu instance logger memastikan semua kejadian mengalir ke file atau stream yang sama.
- Manajemen konfigurasi: satu sumber untuk pengaturan aplikasi menghindari inkonsistensi antar modul.
- Akses antarmuka perangkat keras: satu antarmuka ke perangkat mencegah perintah yang saling bertentangan.
The Benefits and Drawbacks of Using Singletons

Pola Singleton bisa terasa seperti alat andalan ketika Anda membutuhkan satu titik akses ke sumber daya bersama. Ini memberi Anda cara langsung untuk mengelola hal-hal seperti objek konfigurasi atau layanan logging di seluruh aplikasi.
Benefits of Singletons
- Titik akses global menyederhanakan penggunaan antar modul.
- Konservasi sumber daya melalui lazy initialization dapat mengurangi biaya startup.
- Pengurangan duplikasi mencegah adanya beberapa instance yang saling bertentangan pada sumber daya yang mahal.
Drawbacks of Singletons
- Tight coupling: kelas dapat menyembunyikan dependensi dengan mengakses state global.
- Global state: state bersama yang dapat diubah dapat menyebabkan bug yang sulit ditemukan.
- Hidden side effects: metode yang bergantung pada Singleton tidak menampakkan dependensi itu di tanda tangan mereka, membuat penalaran dan pengujian lebih sulit.
Impact on Testing and Coupling
Singleton memperumit unit testing karena mereka memperkenalkan state global yang persisten. Tes berisiko bocor state antar run, dan mem-mock Singleton bisa menjadi canggung. Tim modern sering lebih memilih dependency injection karena membuat dependensi eksplisit dan mudah diganti selama pengujian.3
Balancing the Trade-Offs
Saat memutuskan apakah akan menggunakan Singleton, timbang kenyamanan terhadap keterpeliharaan jangka panjang dan kemampuan untuk dites. Untuk basis kode legacy, refaktor bertahap menuju dependency injection sering menjadi jalan paling aman: pertahankan perilaku sambil mengurangi coupling tersembunyi dan meningkatkan kemampuan pengujian.
Singletons trade simplicity for global state, so choose wisely based on your team’s needs.
Key Takeaways
- Gunakan Singleton secara hemat dan hanya untuk layanan yang benar-benar harus unik.
- Utamakan dependency injection eksplisit untuk decoupling dan kemampuan pengujian yang lebih baik.
- Jika Anda harus menggunakan Singleton, buatlah bersifat lazy dan perhatikan konkurensi serta thread safety.
- Untuk sistem legacy, keluarkan Singleton secara bertahap dengan memperkenalkan interface dan DI di composition root.
How to Implement the Singleton Pattern in TypeScript

Mari beralih dari yang abstrak ke yang praktis dan membangun Singleton modern yang aman-jenis (type-safe) di TypeScript. Rahasianya adalah konstruktor private dan metode static yang bertindak sebagai penjaga gerbang. Kombinasi ini memastikan tidak ada bagian lain dari aplikasi Anda yang dapat membuat instance baru; semua harus lewat satu pintu masuk.2
Untuk contoh praktis, kita akan membuat ConfigManager. Kelas ini memuat dan melayani pengaturan aplikasi, menjamin bahwa setiap komponen membaca dari sumber kebenaran yang sama.
Building a Type-Safe ConfigManager
// A practical example of the Singleton pattern for configuration management.
class ConfigManager {
// 1. A private, static property to hold the single instance.
private static instance: ConfigManager;
// 2. A place to store our configuration data.
private settings: Map<string, any> = new Map();
// 3. The private constructor. This stops `new ConfigManager()` from working anywhere else.
private constructor() {
// In a real app, you'd load from a file, environment variables, or a service.
console.log("Initializing ConfigManager instance...");
this.settings.set("API_URL", "https://api.example.com");
this.settings.set("TIMEOUT", 5000);
}
// 4. The public, static method that controls access to the single instance.
public static getInstance(): ConfigManager {
if (!ConfigManager.instance) {
ConfigManager.instance = new ConfigManager();
}
return ConfigManager.instance;
}
// 5. A regular public method to get a specific setting.
public get(key: string): any {
return this.settings.get(key);
}
}
// TypeScript will stop you from doing this:
// const config = new ConfigManager(); // Error: Constructor of class 'ConfigManager' is private.
Struktur ini menggunakan access modifier TypeScript untuk menegakkan kelas dengan satu instance dan lazy initialization. Konstruktor private dan pola instance static sederhana dan efektif untuk banyak kebutuhan sederhana.
Putting the Singleton to Work in a Service
class ApiService {
private apiUrl: string;
constructor() {
const config = ConfigManager.getInstance();
this.apiUrl = config.get("API_URL");
console.log(`ApiService initialized with API URL: ${this.apiUrl}`);
}
public fetchData(): void {
console.log(`Fetching data from ${this.apiUrl}...`);
// Real data-fetching logic would live here.
}
}
// --- Application Entry Point ---
console.log("Application starting...");
const service1 = new ApiService();
service1.fetchData();
const service2 = new ApiService();
console.log("Application finished.");
Saat Anda menjalankan kode ini, Anda seharusnya melihat pesan inisialisasi dari ConfigManager hanya sekali, membuktikan bahwa kedua service menerima instance yang sama.
Why Singletons Get Such a Bad Rap
Pola Singleton tampak menarik karena sederhana dan memberi Anda objek yang dapat diakses secara global. Yang bisa salah adalah coupling tersembunyi, state global yang dapat diubah, dan mimpi buruk pengujian. Ketika sebuah kelas diam-diam meraih instance global, ia menyembunyikan dependensi yang seharusnya eksplisit di konstruktornya. Ini membuat sistem lebih sulit untuk dipahami dan lebih sulit untuk diuji.3
Nightmares in Concurrency and Global State
Singleton yang berstate dapat menyebabkan kondisi balapan (race conditions) dalam skenario konkuren. Pertimbangkan SessionCounter di mana dua permintaan simultan meningkatkan penghitung yang sama. Tanpa sinkronisasi, keduanya mungkin membaca nilai awal yang sama dan menulis pembaruan yang saling bertentangan. Bug ini bergantung pada timing dan sulit direproduksi.
The Testing Conundrum
Singleton membuat unit test menjadi rapuh karena state dapat bocor antar tes dan mocking menjadi sulit. Tes mungkin mulai bergantung pada urutan eksekusi, dan suite menjadi tidak stabil. Itu sebabnya tim sering mengadopsi dependency injection: membuat dependensi eksplisit dan mudah dimock.
Meskipun masalah ini, Singleton tetap ada di alam liar. Mereka sering menyebar di basis kode setelah diperkenalkan, itulah sebabnya auditing dan refaktor bertahap penting saat memperbaiki arsitektur.
Modern Alternatives to the Singleton Pattern
Setelah melihat risiko yang diperkenalkan Singletons, Anda mungkin bertanya, "Apa yang harus saya gunakan sebagai gantinya?" Dependency injection (DI) adalah pendekatan utama untuk mengelola sumber daya bersama. DI membuat dependensi eksplisit dan meningkatkan kemampuan pengujian serta modularitas.
Dependency Injection Versus Singletons
Bandingkan ApiService asli, yang meraih Singleton, dengan versi yang menerima configuration manager melalui konstruktor.
interface IConfigManager {
get(key: string): any;
}
class ApiService {
private apiUrl: string;
constructor(config: IConfigManager) {
this.apiUrl = config.get("API_URL");
}
}
Sekarang ApiService hanya tergantung pada kontrak IConfigManager. Selama pengujian Anda dapat mengoper fake atau mock, membuat tes cepat dan dapat diprediksi.
By inverting control over who creates dependencies, components become more focused and flexible. This idea is central to the Dependency Inversion Principle.
The Role of IoC Containers
Inversion of Control (IoC) container mengelola pembuatan objek dan injeksi untuk aplikasi Anda. Framework TypeScript populer menyediakan container DI bawaan, seperti NestJS dan Angular, atau library seperti InversifyJS untuk proyek umum.45
Container memungkinkan Anda memilih bagaimana objek dibagikan: transient, scoped, atau lifecycle seperti singleton. Ini memberi Anda manfaat instance bersama tanpa coupling tersembunyi dari Singleton yang dibuat secara programatik.
How to Refactor Singletons in a Legacy Codebase
Bekerjalah secara bertahap. Identifikasi tempat Singleton digunakan, definisikan interface yang jelas yang menjelaskan perilakunya, dan mulai ubah konsumen satu per satu untuk menerima interface melalui constructor injection. Kemudian sambungkan instance konkret di composition root atau biarkan DI container yang mengelolanya.
Step 1: Identify and Isolate the Singleton
Temukan setiap panggilan ke MySingleton.getInstance() dan gambarkan batas tanggung jawab Singleton. Definisikan interface yang mencantumkan metode publik yang Anda butuhkan.
Step 2: Introduce Dependency Injection Incrementally
Refaktor satu konsumen pada satu waktu:
- Ubah konstruktor untuk menerima interface.
- Ganti panggilan langsung
getInstance()dengan panggilan ke instance yang diinjeksi. - Di titik instansiasi, teruskan instance Singleton sampai migrasi selesai.
Ini menjaga aplikasi tetap stabil sambil mengurangi coupling tersembunyi.
Step 3: Replace the Singleton with a Managed Instance
Setelah konsumen menerima dependensi melalui interface, Anda dapat menghapus getInstance() statis dan menjadikan implementasi sebagai kelas biasa dengan konstruktor publik. Buat satu instance di composition root dan teruskan ke tempat yang diperlukan, atau biarkan DI container menangani lifecycle dan scope.
Answering Your Burning Questions About Singletons
Are Singletons Always a Bad Idea?
Tidak selalu. Mereka masuk akal untuk layanan yang benar-benar unik dan tidak berstate, seperti logger pusat atau adapter perangkat keras. Meskipun begitu, DI dan composition root yang terkontrol sering menawarkan perilaku yang sama dengan kemampuan pengujian yang lebih baik.
How Do Singletons Mess Up Unit Testing?
Mereka memperkenalkan state global yang persisten yang dapat bocor antar tes dan membuat mocking sulit. Tes bisa menjadi bergantung pada urutan dan flaky. DI membuat tes lebih sederhana karena mock dapat diinjeksi langsung.
Isn't a Static Class Basically the Same Thing?
Tidak. Kelas statis hanya menampung anggota statis dan tidak bisa diinstansiasi. Singleton memiliki satu instance nyata dan dapat mengimplementasikan interface serta bisa diteruskan sebagai objek. Kedua pendekatan dapat menyebabkan tight coupling, jadi utamakan DI untuk fleksibilitas.
Next Steps for Your Team
Mulailah percakapan tentang di mana, jika ada, sebuah instance bersama tunggal benar-benar diperlukan. Prototipekan DI di modul terisolasi, adopsi standar pengkodean yang jelas, dan gunakan alat untuk mengukur technical debt. Pair programming dan umpan balik berkelanjutan membantu menjaga refactor aman dan efisien.
Ingat, tidak ada pola desain yang merupakan peluru perak. Singleton memiliki tempatnya, tetapi harus digunakan dengan bijak dan dipasangkan dengan interface yang bersih serta aturan kepemilikan yang jelas.
FAQ — Quick Q&A
Q: When is a Singleton appropriate? A: Ketika sebuah sumber daya benar-benar unik dan tidak berstate, seperti logger terpusat atau adapter perangkat keras. Utamakan DI jika memungkinkan.
Q: How can I test code that uses a Singleton now? A: Perkenalkan sebuah interface, refaktor konsumen agar menerima interface, dan injeksikan test double. Lakukan ini secara bertahap untuk menghindari regresi besar.
Q: What’s the safest path to remove Singletons from a legacy app? A: Peta penggunaan, definisikan interface, refaktor konsumen untuk menerima dependensi, lalu buat dan injeksikan satu instance di composition root atau gunakan DI container.
AI menulis kode.Anda membuatnya bertahan.
Di era akselerasi AI, kode bersih bukan hanya praktik yang baik — ini adalah perbedaan antara sistem yang berkembang dan codebase yang runtuh di bawah beratnya sendiri.