Singleton (Tek Nesne) Tasarım Kalıbı (Singleton Design Pattern), bir sınıfın (class) yalnızca bir örneğinin (instance) olmasını ve bu örneğe global erişim (global access) sağlanmasını garanti eden bir tasarım deseni (design pattern)dir. Genellikle konfigürasyon yönetimi (configuration management), veritabanı bağlantıları (database connections), loglama sistemleri (logging systems) gibi tek bir nesnenin yeterli olduğu durumlarda kullanılır.
Singleton Kullanım Amaçları ve Avantajları
- Kaynak Yönetimi (Resource Management): Bellek ve performans optimizasyonu sağlar.
- Veri Tutarlılığı (Data Consistency): Tek nesne kullanımı ile veri bütünlüğünü korur.
- Global Erişim (Global Access): Uygulama genelinde tek bir erişim noktası sunar.
Singleton Ne Zaman Kullanılmalıdır? (When to Use Singleton?)
Singleton kalıbı aşağıdaki durumlarda kullanılmalıdır:
Uygulama genelinde yalnızca bir nesnenin olması gerekiyorsa:
- Örneğin, bir yapılandırma yöneticisi (configuration manager), loglama sistemi (logging system) veya bir iş parçacığı havuzu (thread pool) gibi nesnelerin yalnızca tek bir örneğinin olması gereklidir.
Global erişim noktası (global access point) gerekiyorsa:
- Veritabanı bağlantıları (database connections) gibi sistem kaynaklarının yönetildiği durumlarda, uygulama içindeki tüm bileşenlerin aynı nesneyi paylaşması gerektiğinde Singleton kullanışlıdır.
Veri tutarlılığı sağlanması gerekiyorsa:
- Uygulama genelinde paylaşılan verilerin senkronize edilmesi gerektiğinde (örneğin bir önbellek yöneticisi (cache manager)), farklı iş parçacıkları (threads) aynı veriyi okurken veya yazarken çakışmaların önlenmesi için Singleton deseni kullanılabilir.
Kaynak israfını önlemek için:
- Aynı nesnenin tekrar tekrar oluşturulması yerine, aynı örneğin paylaşılması bellek ve CPU kullanımı açısından avantaj sağlar.
Ancak, gereksiz yere Singleton kullanımı bağımlılığı (dependency) artırabilir ve kodun test edilebilirliğini (testability) zorlaştırabilir. Çok fazla bağımlılığı olan sınıflar için bağımlılık enjeksiyonu (dependency injection) gibi alternatif çözümler düşünülmelidir.
Singleton Kullanım Biçimleri (Different Ways to Implement Singleton)
1. Basit Singleton (Eager Initialization)
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
2. Lazy Initialization Singleton (Tembel Yükleme)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3. Thread-Safe Singleton (İş Parçacığı Güvenli Singleton)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
4. Double-Checked Locking Singleton (Çift Kontrollü Kilitleme)
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
5. Bill Pugh Singleton (Static Inner Class)
public class Singleton {
private Singleton() {}
private static class SingletonHelper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
6. Enum Singleton (Java Özel)
public enum Singleton {
INSTANCE;
public void showMessage() {
System.out.println("Enum Singleton Çalışıyor");
}
}
Gerçek Dünya Örneği: Oyun Skor Yöneticisi (Game Score Manager)
public class ScoreManager {
private static ScoreManager instance;
private int score;
private ScoreManager() {
this.score = 0;
}
public static ScoreManager getInstance() {
if (instance == null) {
synchronized (ScoreManager.class) {
if (instance == null) {
instance = new ScoreManager();
}
}
}
return instance;
}
public void increaseScore(int amount) {
score += amount;
}
public void showScore() {
System.out.println("Mevcut Skor: " + score);
}
}
// Kullanım
public class Main {
public static void main(String[] args) {
ScoreManager score1 = ScoreManager.getInstance();
ScoreManager score2 = ScoreManager.getInstance();
score1.increaseScore(10);
score2.increaseScore(5);
score1.showScore(); // Mevcut Skor: 15
score2.showScore(); // Mevcut Skor: 15
}
}
Bu örnekte, ScoreManager
sınıfı Singleton olarak tasarlanmıştır. Uygulamanın her yerinde tek bir skor yönetici nesnesi kullanılır ve tüm değişiklikler aynı nesne üzerinde gerçekleştirilir.