Ioc ve Castle Windsor Kullanımı

Inversion of control kalıbının yapısı Dependency Injection’a çok benzerdir. Buradan anlayabileceğiniz üzere IoC’nin amacı da DI gibi bağımlılıkları azaltmaktır. IoC’yi öğrenmeden önce Dependency Injection’u öğrenmenizi tavsiye ederim çünkü bu yazıda direkt olarak IoC ile DI arasındaki farklar üzerinden gidilecektir.

Peki nedir Inversion of Control ile Dependcy Injection arasındaki fark ?

Dependency injectionda yaratılmasını istediğimiz nesnelerin yardımcı metotlarlarını kendimiz oluşturmamız gerekir ancak IoC’de containers adını verdiğimiz yardımcı metotlar bu işlemi gerçekleştirir. Bu Container kütüphaneleri ise büyük projelerde yükü bizim üzerimizden almaktadır.  Bu containerların temel kullanım biçimleriyse daha önceden bizim yaptığımız tanımlamaya göre ilgili tipin oluşturularak bize verilmesini amaçlarlar. Internette pek çok container kütüphanesi bulunmaktadır.  .NET’te bunların en meşhuru Windsor Castle’dir.

  Castle Windsor’un yapısı gereği 2 şekilde konfigürasyon yapabilmemize olanak sağlamaktadır. Bunlardan birincisi kod ile (fluent arayüz) tanımlamalarımız yapmak diğer bir şekli ise xml formatında config dosyası kullanmak. Biz fluent arayüz yardımıyla kod tarafında konfigüre edeceğiz.  

 

Aşağıda bir adet IMouse adında interfacemiz tanımlanmıştır.

 interface IMouse
 {
    void Drag();
    void Use();
  }

Ve bu interfaceden türeyen bir adet sınıf

 class Logitech : IMouse
 {

    public void Drag()
    {
     Console.WriteLine("Logitech Mouse Sürüklendi");
    }

    public void Use()
   {
     Console.WriteLine("Logitech Mouse kullanıldı");
   }
}

    Castle Windsor’ın  IoC Container yapısını konfigüre etmek ve  için tüm IoC Container işlemlerini yönetmek için bir basit bir sınıf yazacağız. Bu sınıf temel olarak içerisinde IoC Container’ı yaratacak ve daha sonra da bizim parametre olarak vereceğimiz interface’i implemente eden ve konfigürasyon sırasında tanımladığımız  tipi veriyor olacak.

static class IoClass
{
   private static readonly IWindsorContainer container = new WindsorContainer();

    public static void LogitechFactory()
    {
      container.Register(  Component.For<IMouse>().ImplementedBy<Logitech>()  );
    }

    public static T ResolveMouse<T>()
    {
       return container.Resolve<T>();
    }
}

Yukarıdaki sınıfa biraz daha detaylı bakalım..

  • Container adındaki nesnemiz içerisine nesne konfigurasyonlarını atacağımız ve gerekli zamanlarda bize nesne üretecek nesnemizdir.  
  • LogitechFactory metodumuz çağırıldığında IMouse tipini implemente eden Logitech tipinde bir instancenin container içine eklenmesini bize söyler.
  • ResolveMouse metodu ise jenerik bir metottur. İçerisine aldığı tipe göre gerekli tipin nesnesini geriye döndürür. Yani 

return container.Resolve<T>();    aslında bize Logitech nesnesi geri dönecektir ve biz bunu yaparken hiç new keyworduyle bir nesne yaratmamış olacağız tüm işi container yapacak.

Aşağıda da bir main metodumuz olsun

  static void Main(string[] args)
  {

    IoClass.LogitechFactory();

    IoClass.ResolveMouse<IMouse>.Drag();

    Console.ReadKey();
  }

 

ResolveMouse<IMouse>.Drag();  yukarıda da söylediğim gibi geriye Logitech tipini dönecek ve bizim elimideki metot bir anda Logitech.Drag(); e dönüşecek ve ilgili metot çalıştırılmış olacaktır.

Windsor Castle ile ilgili bazı caseler

* Farklı interfacelerden kalıtılan iki ayrı sınıfı containera atıp kullanmak istersek …

  interface IKlavye
  {
    void Yaz();
  }

  class Kablolu : IKlavye
  {
    public void Yaz()
    {
     Console.WriteLine("Klavyeyle yazıldı");
    }
  }

   IoC classının içerisine bir tanım daha ekleyeceğiz. Tanım

 public static void KlavyeFactory()
 {
    container.Register(
      Component.For<IKlavye>().ImplementedBy<Kablolu>()
   );
 }

şeklinde olacaktır ve main classtan çağırırken

IoClass.KlavyeFactory();

IoClass.Resolve<IKlavye>().Yaz();

* Aynı interfaceden türemiş iki ayrı sınıfa container üzerinden ulaşmak istersek yapacağımız şey nesne konfigurasyonlarına isim eklemek

iki adet mouse classımız olduğunu ve bunların IMouse’dan türediğini varsayalım.

public static void A4TechFactory()
{
   container.Register(
   Component.For<IMouse>().ImplementedBy<A4TechMouse>().Named("a4") );
}
public static void LogitechFactory()
{
  container.Register(
  Component.For<IMouse>().ImplementedBy<Logitech>().Named("logi"));
}

main metotdan üretme işlemi ise

ResolveMouse<IMouse>("a4").Drag();

ResolveMouse<IMouse>("logi").Drag();

şeklinde olacaktır.

LIFESTYE – OLUŞTURULAN NESNELERİN YAŞAM SÜRELERİ

IoC ve Windsor yapısıyla amaçladığımız olay bağımlılıkları azaltıp nesne üretme işlemini Windsor’a vermek peki ya nesnelerin yaşam süreleri hakkında ne söyleyebiliriz?  Resolve metodu geriye ilgili class’ın instancesını döndüğünde aynı instanceımı dönmeli yoksa farklı instancelar mı dönmeli. Bunu nesne hakkındaki bilgileri containera atarken tanımlamak bizim elimizde.

Eğer ki tanımlamayı aşağıdaki şekilde yaparsak nesnenin lifestyle’ı singelton yapıda olacaktır. Yani tek bir nesne üretilecek ve gerektiğinde hep o kullanılacaktır.

  container.Register( Component.For<IMouse>().ImplementedBy<A4TechMouse>() );

Ancak aşağıdaki şekilde tanım yaparsak her resolve metodu çağırıldığında yeni bir nesne üretilecektir yani her nesnenin tipi transient geçiçi olacaktır.  container.Register(

  Component.For<IMouse>().ImplementedBy<A4TechMouse>().LifestyleTransient() );

Bunu çağırmak istediğimiz classın constructurna statik bir sayaç koyup yazdırarak test edebiliriz.

RELEASE – NESNELERI SERBEST BIRAKMA

Gelelim IoC ‘nin faydalarına ve zararlarına.

Faydaları

  • Kodunuz özgür olur. Sınıflar arasındaki bağlaşım kesilir. Sınıflar artık üzümü yiyen ve bağını sormayan bir moda bürünürler -ki bu enfes bir durumdur.
  • Artık kodunuz da Arayüz (Interface) kavramlarını kullanmaya başlarınız.
  • Birim test (Unit test) yazmak inanılmaz kolay bir hale gelir.

Zararları

  • Kodunuzu artık eskisi gibi açıp okumak zorlaşır. Direk kodun içerisinde tıklayıp oradan oraya sınıfların içerisinde gezme şansınız kısmen yok olur çünkü artık kodlar arasındaki bağlaşım kopmuştur. Bu ilişkiler ya XML dosyasında ya da bilgi notlarında(annotation) saklıdır.  Şahsen ben XML dosyası yerine bilgi notu halinde ilişkileri belirtmeyi tercih ederim. Neyse bu ayrı bir konu.
  • Diyelim ki bir xml içerisinde veya bilgi notu verirken (annotation) bir hata yaptınız ve işte bu hatayı bulup düzeltmek biraz daha acı vericidir.

YARARLI SİTELER

“https://www.codementor.io/copperstarconsulting/getting-started-with-dependency-injection-using-castle-windsor-4meqzcsvh”
“https://sitecorecommerce.wordpress.com/2015/11/29/lifestyletransient-castlewindsor-avoid-memory-leak/”
“http://kozmic.net/2010/08/27/must-i-release-everything-when-using-windsor/”

You may also like...

1 Response

  1. ismet tuncer dedi ki:

    Hocam elinize emeğinize sağlık. Çok net şekilde anlatmışsınız. İnsanda soru işareti bırakmıyorsunuz.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir