Ana içeriğe geç

☕ Java Singleton Tasarım Deseni: En İyi Uygulamalar ve Örneklerle Rehber


🎯 Bu Rehberde Ne Öğreneceksiniz?​

Bu rehber, Java’nın Creational (Yaratımsal) Tasarım Desenleri arasında yer alan Singleton desenini derinlemesine anlatır.
Bir sınıfın yalnızca tek bir örneğinin oluşturulmasını sağlayan bu deseni, farklı yaklaşımlar ve güvenli uygulama yöntemleriyle öğreneceksiniz.


🧠 Teknik Özet​

Amaç: Uygulama boyunca yalnızca bir örnek (instance) oluşturmak ve bu örneğe global erişim sağlamak.
Kullanım alanı: Loglama, veritabanı bağlantısı, önbellekleme, thread pool yönetimi.
Öğrenecekleriniz:

  • Singleton prensipleri
  • Eager, Static Block, Lazy ve Thread-Safe yaklaşımlar
  • Bill Pugh yöntemi (önerilen çözüm)
  • Reflection ve Serialization riskleri ve koruma yolları

🧩 Singleton Temel Prensipleri​

Bir sınıfın Singleton olabilmesi için:

  1. Private kurucu → yeni nesne oluşturmayı engeller.
  2. Private static örnek → tek instance’ı saklar.
  3. Public static erişim metodu → dış dünyaya bu örneği döndürür.

⚙️ 1. Erken Başlatma (Eager Initialization)​

Sınıf yüklenirken örnek oluşturulur.

public class EagerInitializedSingleton {
private static final EagerInitializedSingleton ornek = new EagerInitializedSingleton();
private EagerInitializedSingleton(){}
public static EagerInitializedSingleton getInstance() { return ornek; }
}

➡️ Basit ama kullanılmasa bile bellekte yer kaplar.


⚙️ 2. Statik Blok Başlatma (Static Block Initialization)​

Erken başlatma ile benzerdir, fakat hata yönetimi sağlar.


public class StaticBlockSingleton {
private static StaticBlockSingleton ornek;
private StaticBlockSingleton(){}
static {
try { ornek = new StaticBlockSingleton(); }
catch (Exception e) { throw new RuntimeException("Singleton hatası"); }
}
public static StaticBlockSingleton getInstance() { return ornek; }
}

➡️ Exception handling avantajı sunar, ancak hâlâ erken yükleme yapar.


⚙️ 3. Tembel Başlatma (Lazy Initialization)​

Örnek yalnızca ihtiyaç duyulduğunda oluşturulur.


public class LazyInitializedSingleton {
private static LazyInitializedSingleton ornek;
private LazyInitializedSingleton(){}
public static LazyInitializedSingleton getInstance() {
if (ornek == null) ornek = new LazyInitializedSingleton();
return ornek;
}
}

➡️ Kaynak dostu ama çoklu thread ortamında güvenli değildir.


⚙️ 4. Thread-Safe Singleton​

Senkronizasyon ile çoklu iş parçacığında güvenlik sağlar.


public static synchronized ThreadSafeSingleton getInstance() {
if (ornek == null) ornek = new ThreadSafeSingleton();
return ornek;
}

➡️ Thread-safe ama performans maliyeti yüksektir.

🔄 Double-Checked Locking​

Sadece ilk oluşturma sırasında senkronize eder.


if (ornek == null) {
synchronized (ThreadSafeSingleton.class) {
if (ornek == null) ornek = new ThreadSafeSingleton();
}
}

➡️ Performans ve güvenliği dengeler.


⚙️ 5. Bill Pugh Singleton (En Güvenli Yöntem)​

Java 5 sonrası en verimli ve güvenli yöntemdir.


public class BillPughSingleton {
private BillPughSingleton(){}
private static class Yardimci {
private static final BillPughSingleton ORNEK = new BillPughSingleton();
}
public static BillPughSingleton getInstance() { return Yardimci.ORNEK; }
}

➡️ Senkronizasyonsuz thread-safe ve lazy yükleme sağlar.


⚠️ 6. Reflection ile Singleton’ın Bozulması​

Reflection özel kurucuya erişip yeni nesne yaratabilir. Bunu engellemek için kurucuya şu kontrol eklenebilir:


private Singleton() {
if (instance != null) throw new RuntimeException("Yalnızca bir örnek oluşturulabilir!");
}

➡️ Reflection saldırısına karşı koruma sağlar.


🟣 7. Enum Singleton​

Joshua Bloch’un önerdiği en güvenli çözüm:


public enum EnumSingleton {
ORNEK;
public void islemYap() { /* ... */ }
}

➡️ Reflection’a karşı bağışıktır, JVM yalnızca bir örnek üretir.


🧱 8. Serileştirme (Serialization) ve readResolve()​

Serialization yeni nesne oluşturabilir. Bunu engellemek için:


protected Object readResolve() { return getInstance(); }

➡️ Ters serileştirme sonrası aynı instance korunur.


💬 Sıkça Sorulan Sorular (SSS)​

  1. Singleton ve statik sınıf farkı nedir?

Singleton bir nesnedir, statik sınıf değildir; durum (state) tutabilir.

  1. Bill Pugh neden en iyi yöntemdir?

Thread-safe, lazy ve senkronizasyon yükü yoktur.

  1. readResolve() neden gereklidir?

Deserileştirme sırasında yeni nesne oluşmasını engeller.

  1. Singleton nerede kullanılmaz?

Çoklu bağımlılıklı (state-sharing) yapılarda test edilebilirliği düşürür.

  1. Enum Singleton neden tercih edilir?

Hem Reflection hem Serialization’a karşı doğal koruma sağlar.


✅ Sonuç​

Bu rehberde, Java Singleton tasarım desenini farklı uygulama yöntemleriyle öğrendiniz. Artık hangi yaklaşımın performans, güvenlik ve esneklik açısından uygun olduğunu biliyorsunuz.

🚀 Rabisu Bulut üzerinde kendi Java projenizi başlatın ve bu desenleri gerçek bir ortamda test edin.