24 Ocak 2011 Pazartesi

Inversion of Control

Son zamanlarda oldukça popüler olmaya başlayan ve gittikçe de kullanım ihtiyacı artan Inversion of Control (IoC) pattern ile ilgili birkaç bilgi vermekte fayda olduğunu düşünüyorum yeni başlayanlar için ilk adım olarak düşünülebilir.
Inversion of Control (IoC) bir modülün bağımlılık, çözülme, konfigürasyon ve hayat döngüsü konularına çözüm sağlayan dizayn kuralıdır. IoC’nin en önemli özelliği bir modülün bağımlı olduğu diğer assembly bileşenlerinin çözülümünde yatmaktadır.
IoC’nin en iyi bilinen prensibi Dependency Injection Principle’dır (DIP). Makalemizin ilerleyen kısımlarında daha derinlikli olarak inceleyeceğiz şimdilik bir başlangıç yapalım.





IoC Design Pattern
Genel mantığının anlaşılması için örnekleyecek olursak. Bir A sınıfının başka bir sınıf olan B ile bağlantılı olduğunu düşünelim. Bu bağlantı genellikle B sınıfının A sınıfında örneklenmesi ile oluşturulur. Ama bu yaklaşım sınıflar arasında zayıf bir bağlantı oluşturur. B sınıfını, A sınıfını modifiye etmeden kolaylıkla değiştiremezsiniz. Bağlantıyı optimize etmek için yapılandırıcı bir nesne oluşturmamız gereklidir. A(a nesnesi) sınıfı ile B(b nesnesi) sınıfından  seçilen nesneler bu yapılandırıcı üzerinden ilişkilendirilirler bu sayede eğer B sınıfında bir uygulama değişikliğine gidilirse bu değişikliği yapılandırıcı nesne üzerinde değişikliğe giderek A sınıfından herhangi bir değişiklik yapmadan halledebiliriz.
a nesnesi b nesnesinin referans alınmasından sorumlu değil bundan yapılandırıcı nesne sorumludur. Yapılandırıcı kullanılarak A sınıfı ile B sınıfı arasında bir bağ oluşturuluyoruz.
Yapılandırıcı nesne kullanmanın faydalarının daha iyi anlaşılması için IoC kullanmadan ve kullanılarak oluşturduğumuz örneklere bir göz atalım
i1
public class A{                                     
  private B b;        

  public A(){       
    b=new B();
}

Bu örneğimizdeki komutlarda aşağıda belirteceğimiz tasarım kararları vardır
1- A sınıfı B sınıfından bir referansa ihtiyaç duyar
2- B sınıfı somut bir sınıftır ve default bir yapıya sahiptir
3- A sınıfı B sınıfının bir örneğine(instance) sahiptir
4- Başka bir sınıf B sınıfının örneğine ulaşamaz
Eğer herhangi biri yukarda bahsettiğimiz tasarımı değiştirmek isterse direk kodları değiştirmek zorundadır. Örneğin eğer B sınıfı değişirse ve default olmayan bir yapıda olursa ve bu yapıyı C sınıfından alırsa kod aşağıdaki gibi değişir.
i2
public class A{                         
 
  private B b; 
 
  public A(){
   C c=new C();
    b=new B(c);
}
Bu kodlarda da görüldüğü gibi “a” nesnesi “b” ve “c” nesnelerine sahiptir ve B veya C sınıflarında bir değişiklik yapılırsa A sınıfının da değişmesi gerekir. Sonuç olarak bu değişikler zamanla içinden çıkılmaz bir hal almaya başlar. Alternatif olarak IoC kullanan bir frameworke sahip iseniz bu ilişkiyi IoC üzerinden kurabilirsiniz.
i3
public class A{         
 
 
  private B b;                    
                                      
  public A(){                    
  }
 
  public setB(B b){
   this.b=b;
 } 
 
}
Bu şekilde bir kullanım ile
1-      A sınıfı B sınıfından referansa ihtiyaç duyar ama B’nin nasıl örneklendiğini bilmek zorunda değildir.
2-      B bir interface olabileceği gibi abstract veya somut bir sınıf olabilir
3-      A sınıfının örneği kullanmadan önce B sınıfının örneğinin referans alınmasına ihtiyaç duyar
Yukarda saydığımız dizayn kararlarına bakıldığında A sınıfı ile B sınıfı arasında sıkı bir bağ olmadığı görülür. İki sınıfta birbirinden bağımsız olarak değiştirilebilir ve bu değişiklik diğer sınıfı etkilemez.Eğer A veya B sınıfının main metodu değiştirilirse kesinlikle diğer sınıfın main metodunda da değişik yapılmalıdır. Ama “b”  nesnesinin nasıl oluşturulacağı ve kullanılacağı “a” nesnesini ilgilendiren bir durum değildir. IoC framework’u setB() metodunu kullanarak “a” nesnesi ile “b” nesnesini ilişkilendirir.
IoC Frameworkleri
Spring,PicoContainer ve HiveMind gibi bazı açık kodlu frameworkler IoC patternlerini destekler . IoC genel prensipleri basit iken bu frameworkler farklı uygulamaları da destekler ve değişik kazanımlar sağlar.
IoC patternler 3 farklı yolla uygulanabilirler bunlar
-          Setter Based
-          Constructor Based
-          Interface Based
Setter Based IoC
Bu yapı refarans alınan nesnenin refarans nesneye enjekte(Injection) edilmesi için seter metodu kullanır. IoC’un en çok kullanılan tipidir. Spring ve PicoContainer bu yapıyı uygular. Setter Based IoC opsiyonel parametreler alan ve özellikleri yaşam döngüleri süresince değiştirilen nesneler için kullanılabilinir. Dezavantajı ise seter metodunu kullanabilmek için nesnenin bütün özelliklerini tanımlamanız gerekmektedir bu da Nesne tabanlı prensiplerine ters bir kullanım olur bunlar data encapsulation(veri enkapsilasyonu) ve Information hidding(bilgi saklama)’dir.

Constructor Based IoC
Bu yapı refarans objenin set edilmesi için constructor(yapılandırıcı) kullanır. Avantajı sadece kodu yazan kişinin referans alınacak nesneyi bilir. Bütün uygulamalarda kullanılamayabilir örneğin eğer extarnal API kullanılıyorsa default bir yapıya ihtiyaç duyulur bu durumda setter based IoC kullanılır. Constructor based IoC spring uygulamalarında ana yapı olarak kullanılır.
Interface-Based IoC
IoC’un bu tipinde nesne IoC frameworkünün düzenli olarak nesnelerin enjekte edilmesi için kullandığıbelirli bir ara yüzünden implement alır. Avantajlarından biri nesne referanslarının konfigüre edilmesi için dışarıdan bir konfigürasyon dosyasına ihtiyaç yoktur. IoC frameworkleri nesneleri birbirlerine nasıl bağlanacağını tanımlamıştır. EJB kullanımı ile benzerlik gösterir. Apache Avalon bu yaklaşımı temel almıştır ama proje hayata geçirilmedi.
Şimdilik IoC ile ilgili temel yapıları ve birkaç basit örneği gördük önümüzdeki yazımda kurumsal uygulamalarda kullanılabilecek örnekler ile tekrardan bu konu üzerine yazacağım.

Hiç yorum yok:

Yorum Gönder