Makale Özeti

Makalemin bir önceki kısmında unity ile bir uygulamayı nasıl loose coupled hale getirebileceğimizi inceledik. Şimdi ise bu işlemi yaparken transient veya singleton ayarlarını nasıl yapabileceğimizi transient ve singleton kavramlarını açıklayarak anlatmaya çalışacağım.

Makale

Merhabalar,

Makalemin bir önceki kısmında unity ile bir uygulamayı nasıl loose coupled hale getirebileceğimizi inceledik. Şimdi ise bu işlemi yaparken transient veya singleton ayarlarını nasıl yapabileceğimizi transient ve singleton kavramlarını açıklayarak anlatmaya çalışacağım.

Singleton çok basit olmasına karşın belki de farkında olmadan en çok kullandığımız tasarım desenidir. Adından da anlaşıldığı üzere singleton bir sınıfa ait tek bir instance yaratma ve bunu global olarak uygulamanın heryerinden kullanmaktır. Örneğin bir class'dan sadece bir tane oluşturma gereksinim olarak uygulamamızda yer alıyorsa singleton tasarım desenini kullanmamız gerekmektedir.

    public class SingletonOrnek
    {
        protected SingletonOrnek()
        {
        }
        private static SingletonOrnek singletonOrnek = null;
        public static SingletonOrnek SingletonNesne
        {
            get
            {
                if (singletonOrnek == null)
                {
                    singletonOrnek = new SingletonOrnek();
                }
                return singletonOrnek;
            }
        }
    }

Transient ise singleton'un tam tersidir. Yani bir sınıfa her ulaşmak gerektiğinde yeni bir instance alınır. Yeni bir örnek üzerinden işlem yapılır.

Şimdi isterseniz bunu unity ile nasıl uygulayabileceğimizi inceleyelim.

Bunun için unity de hali hazırda 2 tip vardır. Bu tipleri unity'nin config dosyasına dahil etmemiz gerekmektedir. Bu tiplerin tanımlamasını typeAliases içinde yapıp bir alias kullanabileceğimizi gibi direkt tiplerini de yazabiliriz. Ancak ben daha derli toplu olması bakımından alias kullanılmasını tercih ediyorum. Bunun için config'de gerekli tanımlamayı aşağıdaki gibi yapabilirsiniz.

  <typeAliases>
 
    <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
    <typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity"/>
 
  </typeAliases>

 Şimdi ise nesnelerimizi ayağa kaldırırken transient mi yoksa singleton mu kullanacağımızı tanımlamalıyız. Bunun için mappingleri tanımladığımız type nodu altında bu seçimi lifetime nodu ile yapabiliriz. Örnekler aşağıdaki gibidir.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <typeAliases>
      <!-- alias tanımlaması bu şekilde yapılıyor. Config dosyamızda bu tanımlamadan sonra alias tanımlamasını kullanarak bu tiplere erişebileceğiz.-->
      <typeAlias alias="INotificationService" type="ContractService.INotificationService,ContractService"/>
      <typeAlias alias="NotificationService" type="Service.NotificationService,Service"/>
      <!--transient ve singleton tanımlaması-->
      <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
      <typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity"/>
 
    </typeAliases>
    <containers>
      <container>
        <types>
          <!-- Alias tanımlaması ile mapping örneği -->
          <!-- INotificationService kullanılan yerlerde NotificationService tipinin ayağa kaldırılması için -->
          <type type="INotificationService" mapTo="NotificationService">
            <!--lifetime i transient olarak tanimliyoruz-->
            <lifetime type="transient"></lifetime>
            <!--lifetime i singleton olarak tanimliyoruz-->
            <!--<lifetime type="singleton"></lifetime>-->
            <!-- NotificationService içindeki UserData isimli property'nin NotificationService ayağa kalktığında tanımlı mappingle ayağa kaldırılması için -->
            <property name="UserData" >
              <dependency />
            </property>      
          </type>
          <!-- Alias tanımlaması olmadan yapılmış mapping örneği -->
          <type type="ContractData.IUserData,ContractData" mapTo="Data.UserData,Data">
            <!--lifetime i singleton olarak tanimliyoruz-->
            <lifetime type="singleton"></lifetime>
            <!-- UserData ayağa kalktığında herhangi bir propertynin ayağa kalkmasını istemiyoruz.-->
          </type>
        </types>
      </container>
    </containers>
  </unity>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

Şimdi isterseniz singleton ve transient tanımlamalarının kodumuza nasıl etki ettiğine bakalım. Aşağıdaki kodu çalıştıralım.

        static void Main(string[] args)
        {
            Console.WriteLine("Basit bir unity ornegi");
            UI.UIComponent insUIComponent = new UI.UIComponent();
            insUIComponent.Notify("oztamer@hotmail.com");
            Console.WriteLine("Devam etmek icin bir tusa basin.");
            Console.ReadLine();
 
            Console.WriteLine("Transient Ornek, config dosyasinda once transient sonra singleton tanimlamasini kullanin");
            UIComponent ui1 = new UIComponent();
            ui1.SetDefaultEmailAddress("oztamer@hotmail.com");
            string s1 = ui1.GetDefaultEmailAddress();
            Console.WriteLine("1: " + s1);
 
            UIComponent ui2 = new UIComponent();
            string s2 = ui2.GetDefaultEmailAddress();
            Console.WriteLine("2: " + s2);
            Console.ReadLine();
        }

Gördüğünüz gibi UIComponent nesnesinin bir örneğini alıyoruz, Örneği aldığımız anda Service ve Data nesneleri ayağa kalkıyor ve service nesnesinin SetDefaultEmailAddress metodu çağıralarak service nesnesi içerisindeki bir değişkene değer atanıyor. Sonrasında ise bir metodla bu değer okunuyor. Daha sonra yeni bir UIComponent nesnesi oluşturuluyor ve bu nesnenin GetDefaultEmailAddress metodu çağrılıyor.

Transient örneği inceleyelim

Transient çağrıda her iki UIComponent nesnesi içinde farklı service classları oluşturulduğundan 2. sinde geriye bir değer dönmüyor. Çünkü 2. nesneden çağrılan servis nesnesinin içerisinde bulunan değişkene henüz değer atanmamış yani ilkindne çağrılan ile ikinciden çağrılan nesneler tipleri aynı olsa bile farklı referanslarda nesneler.

Singleton örneği inceleyelim.

Singleton çağrıda ise baktığımızda unity her iki UIComponent nesnesine de aynı service instance'ını verdiğini görüyoruz. Yani servis nesnesini isteyen tüm yerlerde aynı nesne referansı dönecektir.

Unity ile singleton ve transient tanımlamaları nasıl yapabileceğimizi gördük bir sonraki makalemde ise interceptor'ları inceleyeceğiz.

Ornek Kodlar