Singleton tasarım deseni: ne zaman kullanılmalı, pratik TypeScript örnekleri ve temel alternatifleri keşfedin.
January 19, 2026 (3mo ago)
TypeScript'te Singleton Deseninde Ustalaşma: Tam Bir Rehber
Singleton tasarım deseni: ne zaman kullanılmalı, pratik TypeScript örnekleri ve temel alternatifleri keşfedin.
← Back to blog
TypeScript'te Singleton Deseninde Ustalaşma: Tam Bir Rehber

Yazılım geliştirme dünyasında, bazı araçlar güçlüdür ama dikkatle kullanılmalıdır. Singleton deseni de bunlardan biridir. Temelde basit bir kavramdır: bir sınıfın yalnızca tek bir örneğe sahip olmasını sağlamak ve ona erişmek için tek, küresel bir yol sunmak.1
Bunu tüm uygulamanız için merkezi bir yapılandırma yöneticisi veya özel bir günlükleme servisi gibi düşünebilirsiniz. Birden fazla, çelişen yapılandırma nesnesinin ortalıkta dolaşmasını istemezsiniz; aynı şekilde, birbirleriyle yarışan günlükleyici örnekleriyle günlük kayıtlarının farklı dosyalara dağılmasını da istemezsiniz. Singleton bu çoğaltmaları engelleyerek düzen getirir, bellek tasarrufu sağlar ve kaosu önler. Paylaşılan kaynaklara erişimi yönetmek için temel bir desendir.
Singleton Deseni Nedir ve Ne Zaman Kullanışlıdır?
Bir ortaçağ krallığını ve yalnızca bir tane resmi Kraliyet Yazmanı olduğunu hayal edin. Bu kişi, kraliyet fermanlarını kaydetmeye yetkili tek kişidir. Bu, her kanun ve duyurunun tutarlı, düzgün yetkilendirilmiş ve tek, kesin bir defterde saklanmasını sağlar. Herkes yazman olmaya karar verebilseydi, krallık hızla çelişkili kayıtlarla ve büyük karışıklıkla kaosa sürüklenirdi.
Singleton tasarım deseni yazılımınız içinde tam olarak bu ilkeyle çalışır. Bir sınıfın yalnızca tek bir nesne oluşturulmasını kısıtlamak birincil görevidir. Bu tek ve yalnız örnek belirli bir görev için gerçeklik kaynağı olur ve kod tabanınızın her yerinden kolayca erişilebilir. Böylece asla çoğaltılmaması gereken kaynaklar üzerinde kontrol sağlamış olursunuz.
Temel Amaç ve Benzetme
Singleton sadece insanların yeni nesneler oluşturmasını engellemekle ilgili değildir; kontrolü merkezileştirmekle ilgilidir. Nasıl ki Kraliyet Yazmanı krallığın resmi kayıtlarına tek bir erişim noktası sağlıyorsa, bir Singleton örneği de paylaşılan kaynağa evrensel olarak erişilebilen bir kapı sunar. Uygulamanızın farklı bölümlerinin kendi izole ve potansiyel olarak çelişen sürümlerini yaratmasını engeller.
Bir veritabanı bağlantı havuzu klasik bir örnektir. Uygulamanızdaki her bileşenin veritabanına kendi ayrı bağlantısını açmasını istemezsiniz—bu sunucu kaynaklarını tüketmek ve performansı durdurmak için kesin bir yoldur. Bunun yerine bir Singleton bir bağlantı havuzunu yönetebilir ve ihtiyaç duyulduğunda bunları verimli şekilde dağıtabilir.
Temel fikir basit ama güçlüdür: bir sınıf, bir örnek, bir küresel erişim noktası. Bu yapı, belirli bir kaynağa yapılan tüm etkileşimlerin tek, kontrollü bir kanal aracılığıyla yapılmasını garanti eder.
Singleton Desenine Genel Bakış
| Özellik | Açıklama ve Gerekçe |
|---|---|
| Tek Örnek | Sınıf, uygulamanın yaşam döngüsü boyunca yalnızca bir örneğe sahip olacak şekilde tasarlanır; genellikle bu, özel (private) bir yapıcıyla (constructor) zorlanır. |
| Küresel Erişim Noktası | Statik bir yöntem (ör. getInstance()) örneğe kodun herhangi bir yerinden erişmek için tek, iyi bilinen yolu sağlar. |
| Tembel Başlatma | Tek örnek genellikle ilk istekte oluşturulur, uygulama başlatılmasında değil; bu, performansı artırabilir. |
| Durum Yönetimi | Uygulama ayarları veya bir kullanıcı oturumu gibi belirli bir küresel durum parçası için merkezileştirilmiş bir yer olarak hareket eder. |
Bu tablo, desenin neden var olduğunu düzgünce özetler: doğası gereği tek olan kaynaklar için tek, küresel olarak erişilebilir bir örneği zorlamak.
Pratik Kullanım Örnekleri
Singleton deseninin eleştirmenleri olsa da, meşru kullanımları da vardır. Sistem içinde doğası gereği benzersiz olan bir kaynağınız olduğunda en etkilidir.
Singleton mantıklı olan birkaç senaryo:
- Günlükleme servisleri: tek bir logger örneği tüm olayların aynı dosya veya akıma yönlendirilmesini sağlar.
- Yapılandırma yönetimi: uygulama ayarları için tek bir kaynak modüller arası tutarsızlığı önler.
- Donanım arayüz erişimi: bir cihaza tek bir arayüz çakışan komutları önler.
Singleton Kullanmanın Yararları ve Dezavantajları

Singleton deseni, paylaşılan bir kaynağa tek erişim noktası gerektiğinde güvenilir bir araç gibi görünebilir. Tüm uygulama genelinde bir yapılandırma nesnesi veya günlükleme servisi gibi şeyleri yönetmek için doğrudan bir yol sunar.
Singleton'ların Yararları
- Küresel erişim noktası modüller arası kullanımı basitleştirir.
- Tembel başlatma yoluyla kaynak tasarrufu, başlangıç maliyetini azaltabilir.
- Tekrarlamayı azaltmak pahalı kaynakların birden fazla, çelişen örneğinin oluşmasını engeller.
Singleton'ların Dezavantajları
- Sıkı bağımlılık (tight coupling): sınıflar bağımlılıklarını küresel durumdan gizleyebilir.
- Küresel durum: paylaşılan değiştirilebilir durum bulunması zor bulunan hatalara yol açabilir.
- Gizli yan etkiler: Singleton'a dayanan yöntemler bu bağımlılığı imzalarında göstermez, bu da akıl yürütmeyi ve test etmeyi zorlaştırır.
Test ve Bağlanma Üzerindeki Etkisi
Singleton'lar küresel, kalıcı durum getirdiği için birim testlerini karmaşıklaştırır. Testler arasında durum sızma riski vardır ve bir Singleton'ı taklit etmek (mock) garipleşebilir. Modern ekipler bağımlılık enjeksiyonunu (DI) tercih eder çünkü bu, bağımlılıkları açık hale getirir ve testlerde kolayca değiştirilebilmesini sağlar.3
Takasların Dengelenmesi
Singleton kullanıp kullanmamaya karar verirken kolaylığı uzun vadeli sürdürülebilirlik ve test edilebilirlikle tartın. Miras (legacy) kod tabanlarında, bağımlılık enjeksiyonuna kademeli refaktörler genellikle en güvenli yoldur: davranışı korurken gizli bağlanmayı azaltır ve test edilebilirliği iyileştirir.
Singleton'lar basitliği küresel durumla takas eder; bu yüzden ekibinizin ihtiyaçlarına göre akıllıca seçin.
Önemli Çıkarımlar
- Singleton'ları nadiren ve gerçekten benzersiz olması gereken servisler için kullanın.
- Daha iyi gevşek bağlanma ve test edilebilirlik için açık bağımlılık enjeksiyonunu tercih edin.
- Singleton kullanmak zorundaysanız, onu tembel (lazy) yapın ve eşzamanlılık (concurrency) ve iş parçacığı güvenliği (thread safety) konusunda dikkatli olun.
- Miras sistemler için, kompozisyon kökünde arabirimler ve DI tanıtarak Singleton'ları kademeli olarak kaldırın.
TypeScript'te Singleton Desenini Nasıl Uygularsınız

Soyuttan pratiğe geçelim ve TypeScript'te modern, tür güvenli (type-safe) bir Singleton inşa edelim. Gizli sos, private bir constructor ve kapıcı (gatekeeper) olarak davranan static bir yöntemdir. Bu kombinasyon uygulamanızın başka hiçbir yerinin yeni bir örnek oluşturamamasını sağlar; herkes tek giriş noktasından geçer.2
Uygulamalı örneğimiz için bir ConfigManager oluşturacağız. Bu sınıf uygulama ayarlarını yükler ve sunar; her bileşenin aynı gerçeklik kaynağını okumasını garanti eder.
Tür Güvenli (Type-Safe) Bir ConfigManager Oluşturma
// 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.
Bu yapı, TypeScript'in erişim belirteçlerini (access modifiers) kullanarak tek örnekli bir sınıf ve tembel başlatmayı zorlar. private constructor ve static instance deseni birçok basit ihtiyaç için doğrudan ve etkilidir.
Bir Serviste Singleton'ı Kullanma
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.");
Bu kodu çalıştırdığınızda, ConfigManager'dan gelen başlatma mesajını yalnızca bir kez görmelisiniz; bu da her iki servisin aynı örneği aldığını kanıtlar.
Neden Singleton'lar Bu Kadar Kötü Bir İtibar Edindi?
Singleton deseni çekici görünür çünkü basittir ve küresel erişilebilen bir nesne sunar. Sorunların kaynağı genellikle gizli bağımlılık, küresel değiştirilebilir durum ve test kabuslarıdır. Bir sınıf gizlice küresel bir örneğe uzandığında, inşa edilmesi gereken bir bağımlılığı yapıcısında (constructor) açık hale getirmez. Bu da sistemi anlamayı ve test etmeyi zorlaştırır.3
Eşzamanlılık ve Küresel Durum Kabusları
Durum tutan Singleton'lar eşzamanlı (concurrent) senaryolarda yarış koşullarına (race conditions) yol açabilir. İki eşzamanlı isteğin aynı sayacı artırdığı bir SessionCounter düşünün. Senkronizasyon olmadan her ikisi de aynı başlangıç değerini okuyup çakışan güncellemeler yazabilir. Bu hatalar zamanlamaya bağlıdır ve yeniden üretmesi zordur.
Test Etme İkilemi
Singleton'lar birim testlerini kırılgan hale getirir çünkü durum testler arasında sızabilir ve taklit (mock) etmek zorlaşır. Testler yürütme sırasına bağlı hale gelebilir ve test paketi kararsızlaşır. Bu yüzden ekipler genellikle bağımlılık enjeksiyonunu benimser: bu, bağımlılıkları açık hale getirir ve mock'lamayı kolaylaştırır.
Bunlara rağmen, Singleton'lar hâlâ yaygındır. Bir kez kod tabanına girdikten sonra yayılma eğilimi gösterirler; bu nedenle mimariyi iyileştirirken denetim (audit) ve kademeli refaktörler önemlidir.
Singleton Desenine Modern Alternatifler
Singleton'ların getirdiği riskleri gördükten sonra muhtemelen "Bunun yerine ne kullanmalıyım?" diye soruyorsunuzdur. Bağımlılık enjeksiyonu (DI), paylaşılan kaynakları yönetmek için başvurulacak yaklaşımdır. DI bağımlılıkları açık hale getirir ve test edilebilirlik ile modülerliği geliştirir.
Bağımlılık Enjeksiyonu ve Singleton'lar
Singleton'a uzanan orijinal ApiService ile bir yapılandırma yöneticisini yapıcı parametresiyle kabul eden bir versiyonunu karşılaştırın.
interface IConfigManager {
get(key: string): any;
}
class ApiService {
private apiUrl: string;
constructor(config: IConfigManager) {
this.apiUrl = config.get("API_URL");
}
}
Artık ApiService yalnızca IConfigManager sözleşmesine (contract) bağımlıdır. Testlerde sahte (fake) veya mock bir örnek geçirebilirsiniz; bu da testleri hızlı ve öngörülebilir yapar.
Bağımlılıkları kimin oluşturduğu üzerindeki kontrolü tersine çevirerek, bileşenler daha odaklı ve esnek hale gelir. Bu fikir Bağımlılık Tersine Çevirme Prensibi'nin (Dependency Inversion Principle) merkezindedir.
IoC Konteynerlerinin Rolü
Kontrolün Tersine Çevrilmesi (Inversion of Control - IoC) konteyneri, nesne oluşturmayı ve uygulamanız için enjeksiyonu yönetir. Popüler TypeScript çerçeveleri, NestJS ve Angular gibi, yerleşik DI konteynerleri sunar veya genel projeler için InversifyJS gibi kütüphaneler kullanılabilir.45
Konteynerler nesnelerin nasıl paylaşıldığını seçmenize izin verir: geçici (transient), kapsamlı (scoped) veya singleton-benzeri yaşam döngüleri. Bu, programatik bir Singleton'ın gizli bağlanması olmadan tek bir paylaşılan örneğin faydalarını sağlar.
Miras Kod Tabanında Singleton'ları Nasıl Refaktörlersiniz
Kademeli çalışın. Singleton'ın nerede kullanıldığını tespit edin, sorumlulukları etrafında net bir sınır çizin ve davranışını tanımlayan açık bir arayüz oluşturun. Ardından tüketicileri (consumers) teker teker yapıcı enjeksiyonuyla arayüzü kabul edecek şekilde değiştirmeye başlayın. Sonra somut örneği kompozisyon kökünde bağlayın veya bir DI konteynerinin yönetmesine izin verin.
Adım 1: Singleton'ı Belirleyin ve İzole Edin
MySingleton.getInstance() çağrısının her yerini bulun ve Singleton'ın sorumlulukları etrafında bir sınır çizin. İhtiyacınız olan genel yöntemleri listeleyen bir arayüz tanımlayın.
Adım 2: Bağımlılık Enjeksiyonunu Kademeli Tanıtın
Tüketiciyi bir kerede bir tane refaktörleyin:
- Yapıcıyı arayüzü kabul edecek şekilde değiştirin.
- Doğrudan
getInstance()çağrılarını enjeksiyonla alınan örnek çağrılarına değiştirin. - Örnekleme noktasında, tam geçiş tamamlanana kadar Singleton örneğini geçirin.
Bu, gizli bağlanmayı azaltırken uygulamanın kararlı kalmasını sağlar.
Adım 3: Singleton'ı Yönetilen Bir Örnekle Değiştirin
Tüketiciler arayüz üzerinden bağımlılık aldığında, statik getInstance()'ı kaldırabilir ve uygulamayı normal bir sınıf haline getirip herkese açık (public) bir constructor verebilirsiniz. Kompozisyon kökünde tek bir örnek oluşturup gerektiği yere geçirin veya bir DI konteynerinin yaşam döngüsü ve kapsamı yönetmesine izin verin.
Singleton'lar Hakkında Aklınızı Kurcalayan Sorulara Cevaplar
Singleton'lar Her Zaman Kötü Bir Fikir mi?
Her zaman değil. Merkezi bir logger veya bir donanım adaptörü gibi gerçek anlamda benzersiz, durumsuz (stateless) servisler için mantıklı olabilirler. Yine de DI ve kontrollü bir kompozisyon kökü genellikle aynı davranışı daha iyi test edilebilirlik ile sunar.
Singleton'lar Birim Testlerini Nasıl Berbat Eder?
Global, kalıcı durum tanıtırlar; bu durum testler arasında sızabilir ve mock'lamayı zorlaştırır. Testler yürütme sırasına bağımlı ve kararsız hale gelebilir. DI, mock'ların doğrudan enjeksiyonunu sağlayarak testleri basitleştirir.
Statik Bir Sınıf Temelde Aynı Şey Değil mi?
Hayır. Statik bir sınıf yalnızca statik üyeleri barındırır ve örneklendirilemez. Bir Singleton gerçek bir örneğe sahiptir ve arayüzleri (interface) uygulayabilir ve nesne olarak geçirilip kullanılabilir. Her iki yaklaşım da sıkı bağlanmaya yol açabilir, bu yüzden esneklik için DI'ı tercih edin.
Ekibiniz İçin Sonraki Adımlar
Gerçekte tek bir paylaşılan örneğin gerçekten gerekli olduğu yerler hakkında bir tartışma başlatın. İzole bir modülde DI prototipi oluşturun, net kodlama standartları benimseyin ve teknik borcu ölçmek için araçlar kullanın. Eşli programlama (pair programming) ve sürekli geri bildirim refaktörleri güvenli ve verimli tutmaya yardımcı olur.
Unutmayın, hiçbir tasarım deseni sihirli çözüm değildir. Singleton'ların bir yeri vardır, ama dikkatli kullanılmalı ve temiz arayüzler ile net sahiplik kurallarıyla eşleştirilmelidir.
SSS — Hızlı Soru&Cevap
S: Singleton ne zaman uygundur? C: Bir kaynak gerçekten benzersiz ve durumsuz olduğunda, örn. merkezi bir logger veya bir donanım adaptörü. Mümkün olduğunda DI'ı tercih edin.
S: Şimdi Singleton kullanan kodu nasıl test edebilirim? C: Bir arayüz tanıtın, tüketicileri arayüzü kabul edecek şekilde refaktörleyin ve test double (sahte) enjeksiyonu yapın. Büyük çaplı regresyonlardan kaçınmak için bunu kademeli yapın.
S: Miras bir uygulamadan Singleton'ları çıkarmanın en güvenli yolu nedir? C: Kullanımları haritalayın, arayüzler tanımlayın, tüketicileri bağımlılık kabul edecek şekilde refaktörleyin, sonra kompozisyon kökünde tek bir örnek oluşturun veya bir DI konteyneri kullanın.
AI kod yazar.Siz onu uzun süre dayanır hale getirirsiniz.
AI hızlanması çağında, temiz kod sadece iyi bir uygulama değil — ölçeklenen sistemlerle kendi ağırlığı altında çöken kod tabanları arasındaki farktır.