Tasarım Kalıpları: Singleton (Tek Nesne) – III – Enum Kullanımı

Daha önceki singleton yazılarında, bu kalıbın, alışıla gelmiş haliyle (yani private yapılandırıcı hali) nasıl kurgulandığını ve üzerinde yaptığımız bazı değişikliklerin sonuçlarından bahsetmiştik. Açıkçası bu yazılarda ele alınan yöntem singleton kalıbını oluşturmanın tek yolu da değildir. “enum” yapısını kullanarak da tek bir nesneye sahip bir sınıf oluşturabiliriz.

Malum, “enum” Java’ya SE 5 ile birlikte katılmış anahtar kelimelerdendir. enum, İngilizce’deki “enumeration” yani sıralama kelimesinin kısaltılmış halidir. enum anahtar kelimesiyle, aynı “class” ve “interface” kelimelerinde olduğu gibi yeni bir tip oluştururuz. enum tipinin sahip olabileceği tüm nesneler, enum sınıfı içinde tanımlanırlar. Bu yeni tip aslında özel bir sınıftır ve yapısından dolayı bize getirdiği bazı kısıtları vardır:

  • enum, abstract ya da final olamaz.
  • Her enum, java.lang.Enum‘ın bir alt sınıfıdır.
  • Bir enum tipinin, kendi içinde tanımlanan ve sabite olan, enum nesneleri dışında hiç bir nesnesi yaratılamaz. Bu nesneler de bir enum tipinin metninde ilk sırada gelen üye değişkenler olmalıdır. Yani bir enum sınıfının farklı üye değişkenleri varsa, enum tipinde olan en önce olmalıdır.
  • Tüm enum tipindeki değişkenler otomatik olarak public, static ve final olarak tanımlanırlar.
  • Bir enum tipinin tüm yapılandırıcıları (constructor) private olmak zorundadır, yani bir enum tipinde public ve protected yapılandırıcı tanımlanamaz. Bir enum tipinde varsayılan erişimde bir yapılandırıcı tanımlansa bile bu yapılandırıcı private olur. Hiç yapılandırıcı tanımlanmazsa derleyici bir tane varsayılan private yapılandırıcı tanımlar.
  • Bir enum tipinin yapılandırıcıları çağrılamaz.
  • Bir enum tipinin abstract metodu olamaz. Eğer bir enum tipinin abstract bir metodu olursa, tüm enum değişkenleri bu metodu sınıf içinde ezmek zorundadırlar.
  • enum sabiteleri için parametre geçilebilir, bu durumda bu parametreleri alan yapılandırıcıların olması gereklidir.
  • Bir enum tipinin yapılandırıcıları, o tipteki final olmayan statik üye değişkenlerine ulaşamazlar.
  • java.lang.Enum‘ın “equals()“, “hashCode()” ve “clone()” metotları finaldır.
  • Bir enum tipi, kendi tipindne değişkenler dışında farklı tipte üye değişkenlere sahip olabilir, bu farklı tipteki üye değişkenleri parametre olarak alacak yapılandırıcılara sahip olabilir.

Yukarıda “enum tipinin sahip olabileceği tüm nesneler, enum sınıfı içinde tanımlanırlar” demiştik. Dolayısıyla sadece bir tek nesnesi olan bir enum tip tanımlarsak bu bir singleton olur. Aşağıdaki koda bakalım:

package org.javaturk.dp.pattern.gof.creational.singleton;

public enum EnumSingleton {
		
	SINGLETON;
	
	// In fact no need for this method because SINGLETON is already public.
	public static EnumSingleton getInstance(){
		return SINGLETON;
	}
}

 

Bu durumda istemci kodumuz şöyle olacaktır:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class EnumSingletonClient {

	public static void main(String[] args) {
		EnumSingleton instance1 = EnumSingleton.SINGLETON;
		EnumSingleton instance2 = EnumSingleton.getInstance();
		
		if(instance1 == instance2)
			System.out.println("The same!");
		else
			System.out.println("Different!");
		
	}
}

 

EnumSingletonClient sınıfındaki main metot çalıştırıldığında ise konsola “The same” yazılacaktır.

Yukarıdaki enum sınıfında, daha önceki yaygın singleton sınıflarında olduğu gibi “private static int count;” tanımlayıp yapılandırıcıda da “count++; name = “Singleton” + count;” cümleleri ile değerini arttırıp, nesnenin name özelliğini belirleme  yoluna gitmedik, daha doğrusu gidemedik çünkü yukarıda da yazdığımız gibi enum tipinin yapılandırıcıları, o tipteki final olmayan statik üye değişkenlerine ulaşamazlar.

Açıkçası, sonradan çıkmış olmasına rağmen enum tipini kullanan bu yaklaşımın önce ele aldığımız yaygın yaklaşıma bazı üstünlükleri vardır. Çünkü yaygın yaklaşımda, singleton olan nesneden daha fazla nesne yaratmak bazı özel durumlarda söz konusudur. Örneğin reflection kullanarak yapılandırıcısı private olsa bile yeni nesneler oluşturabilirsiniz. Ya da “clone()” metodunu kullanarak var olan nesnenin kopyalanması söz konusudur. Ayrıca singleton olan nesneyi serialized yapıp, sonra deserialized yaparsanız, elinizde bir başka nesne daha oluşacaktır. Bu üç durum genel olarak yaygın olan yaklaşımın en problemli olan üç noktasıdır. Ayrıca yaygın yaklaşımda sonradan yüklemeli durumu tercih ettiğinizde, “synchronized” ve “volatile” anahtar kelimelerini kullanmazsanız başınızın derde gireceğini daha önce burada göstermiştik. Dolayısıyla enum kullanan singleton, eğer yukarıdaki kısıtlar sizi zorlamıyorsa, yaygın yapıya göre çok daha güvenli ve kullanışlıdır. Nitekim Jashua Block “Effective Java” isimli güzel kitabının ikinci baskısındaki singleton tartışımasın şöyle bitiriyor:

“This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.”

 

Bu yazı toplam 1121 defa görüntülenmiştir.