Singleton (Tek Nesne) Design Pattern

Uygulama geliştirirken en popüler tasarım desenlerinden biri singleton yani tek nesne tasarım desenidir.

İsminden de anlaşılacağı üzere singleton tasarım deseni,  hazırlayacağımız sınıftan sadece bir örneğinin oluşturulmasını sağlar. Bu sayede nesnenin kopyalanmasını yada yeni bir tane oluşturmasını engeller ve nesneye ihtiyaç duyulduğunda o nesnenin daha önceden oluşturulan örneği çağırır.

Ne zaman kullanırız?

Veritabanı bağlantılarında, port bağlantılarında, yada dosya işlemleri gibi tek bir nesneye ihtiyaç duyduğumuz zamanlarda kullanırız.

 

Nasıl Yaparız?

Daha önceki yazılarımı okuduysanız dışarıdan nesne oluşturduğumuzda ilk başta construct yani kurucu metotun çalıştığını bilmeniz gerekir. Construct sihirli metotunu private yada protected yaparsak nesne oluşturmasını yalnızca sınıfın içinde veya miras alan sınıf içinde tanımlayabiliriz.

public class SingletonObject
{
    // Nesnemizin daha önceden oluşturulmadığını anlayabilmemiz için statik instance özelliği tanımlıyoruz.
    private static SingletonObject instance = null;
 
    //Sınıfımızın construct (kurucu) metodunu private yada protected tanımlıyoruz.
    private SingletonObject()
    {
        // oluşturulma sırasında kullanacağımız kodlar
    } 
 
    // Dışarıdan sınıfımızı çağıracağımız metodumuz.
    public static SingletonObject getInstance()
    {
        // eğer daha önce örnek oluşturulmamış ise sınıfın tek örneğini oluştur
        if(instance == null)
        {
            instance  = new SingletonObject();
        }
        return instance;
    } 
 
}

Yukarıdaki gibi bir sınıf oluşturduğumuzda dışarıdan new SingletonObject() dediğimizde hata verdiğini göreceksiniz. Bir önceki yazımda tasarım desenlerinin programlama dili gözetmeksizin bir standardı olduğunu söylemiştim, bunu pekiştirmek adına bir de PHP de nasıl olacağını görelim.

<?php
class SingletonObject
{
    // Nesnemizin daha önceden oluşturulmadığını anlayabilmemiz için statik instance özelliği tanımlıyoruz.
    private static $instance = null;
    
    //Sınıfımızın construct (kurucu) metotu private yada protected tanımlıyoruz.
    private function __construct()
    {
        // oluşturulma sırasında kullanacağımız kodlar
    }

    // Dışarıdan sınıfımızı çağıracağımız metodumuz.
    public static function getInstance()
    {
        // eğer daha önce örnek oluşturulmamış ise sınıfın tek örneğini oluştur
        if (static::$instance == null) {
            static::$instance = new static();
        }
        
        return static::$instance;
    }
}

Gördüğünüz gibi mantık aynı, peki bu işlemler yeterli mi, başka türlü nesne oluşturabilir mi? Tabi ki evet, sınıftan yeni bir örnek oluşturamasak da var olan örneği kopyalayabiliriz, bu yüzden bunuda engellemek için clone sihirli metoduna düzenleme yapmalıyız.

Son olarak JAVA'ya özgü thead (kanal) yapısı sayesinde birden fazla kanaldan aynı anda  getInstance metoduna istek yaparsak ve daha önce oluşturmadıysak birden fazla örnek oluşturmuş oluruz, bunu engellemek içinde metodumuzun başına synchronized anahtar kelimesini ekleyerek bu işlemleri sıraya koyar ve birden fazla oluşmasını engelleriz.

Lafı fazla uzatmadan son haline bakalım

public class SingletonObject
{
    // Nesnemizin daha önceden oluşturulmadığını anlayabilmemiz için statik instance özelliği tanımlıyoruz.
    private static SingletonObject instance = null;
 
    //Sınıfımızın construct (kurucu) metodunu private yada protected tanımlıyoruz.
    private SingletonObject()
    {
        // oluşturulma sırasında kullanacağımız kodlar
    } 
 
    // Dışarıdan sınıfımızı çağıracağımız metodumuz.
    // synchronized anahtar kelimemiz ile metodun aynı anda çalışmasını engelledik.
    public synchronized static SingletonObject getInstance()
    {
        // eğer daha önce örnek oluşturulmamış ise sınıfın tek örneğini oluştur
        if(instance == null)
        {
            instance  = new SingletonObject();
        }
        return instance;
    }

    //Sınıfı clone sihirli metoduyla kopyalamaya çalıştığımızda CloneNotSupportedException ile kopyalanmasını engelliyoruz.
    @Override
    public Object clone() throws CloneNotSupportedException
    {
        throw new CloneNotSupportedException("Ben eşsiz bir parçayım");
    }
 
}

Yukarıda PHP'den de bahsettik o zaman onunda son haline bakalım

<?php
class SingletonObject
{
    // Nesnemizin daha önceden oluşturulmadığını anlayabilmemiz için statik instance özelliği tanımlıyoruz.
    private static $instance = null;
    
    //Sınıfımızın construct (kurucu) metotu private yada protected tanımlıyoruz.
    private function __construct()
    {
        // oluşturulma sırasında kullanacağımız kodlar
    }

    // Dışarıdan sınıfımızı çağıracağımız metodumuz.
    public static function getInstance()
    {
        // eğer daha önce örnek oluşturulmamış ise sınıfın tek örneğini oluştur
        if (static::$instance === null) {
            static::$instance = new static();
        }
        
        return static::$instance;
    }

    // dışarıdan kopyalanmasını engelledik
    private function __clone()
    {
    }

    // unserialize() metodu ile tekrardan oluşturulmasını engelledik
    private function __wakeup()
    {
    }
}

Bu yazıma özel hem JAVA hem de eski dost PHP'de singleton tasarım deseni nasıl uygulanır ona değindim. Bundan sonraki yazılarımda yüksek ihtimal yalnızca JAVA ile ilerleyeceğim ama yukarıdaki örnekten de anlaşılacağı üzere mantıkları birebir aynıdır. Yani bu tasarım desenlerinin dili yok.

Kendinize iyi bakın :)


Kategoriler: Programlama PHP JAVA