|  | 
        
            | 
                    
                        | Dependency Inversion Principle (DIP) |  |  
                        | 
	
    
		
            | Gönderiliyor lütfen bekleyin... | 
 |  | 
        
            | Merhaba bu makalede 
  sizlere nesneye yönelik yazılım tasarımının temel prensiplerinden olan Dependency 
  Inversion Principle(DIP)  hakkında bilgi verip ufak bir örnekler 
  anlatmaya çalışacağım.Türkçe olarak ifade etmeye çalışırsak buna bağımlılığın 
  ters çevrilmesi diyebiliriz. 
 Klasik prosedürel 
  programlamada stilinde geliştirilen yazılımlarda genellikle üst seviyeli modüller, 
  sınıflar vb.. alt seviyeli modüllere bağımlıdır. Bunun en önemli dezavantajlarından 
  biriside alt seviyeli modüller ya da sınıflar daha sık değişebilir ve de bu 
  değişimden de üst seviyeli modüller etkilenir. Bu değişimin sonucunda  
  üst seviyeli modüllerde kod içerisinde değişiklik yapmak ve zincirmele 
  olarak tüm modülleri derleyip yayınlamak gerekir. Sonuçta ufak değişikliklerden 
  bile en üst seviyeye kadar etkilenebilen yönetilmesi zor bir model oluşur. Bu 
  tarz modeller modüler olarak tekrar kullanılabilir gözüksede üst seviyeden 
  alt seviyeye kadar bağımlılık zinciri olduğu için tekrar kullanmak istediğimiz 
  modülle birlikte diğer modülleri de dahil etmemiz gerekir.Bu da bize gerçek 
  anlamda bir tekrar kullanılabilirlik sağlamaz çünkü gerçek anlamda birbirinden 
  soyutlanmış modüller yoktur. Malesef günümüzde modern birçok nesneye yönelik 
  programlama dilinde dahi bu şekilde yazılım geliştirilmektedir çünkü kullandığımız 
  programlama dilinin nesneye yönelik olması bizim nesneye yönelik yazılım geliştireceğimiz 
  anlamına gelmez. Aşağıda örnek olarak prosedürel yöntem ve Dependency 
  Inversion Principle(DIP) yöntemi ile tasarlanmış modelleri görebiliriz.
 
 
 
   
 
  
 Yazılım geliştirmede 
  genellikle Tekrar Kullanılabilirlik ve  Esneklik 
  terimleri sıkça duyarız. Peki gerçekten bu terimler bize ne ifade eder? Tekrar 
  kullanılabilir ve esnek yazılımları nasıl geliştirebiliriz ?Bu gibi soruların 
  cevabı profosyonel yazılım geliştirmede oldukça önemlidir. Önce bağımlılık ve 
  tekrar kullanılabilirlik ile başlayalım.
 
 Bağımlılık teriminide 
  kısaca özetlersek bir sınıfın başka bir sınıfa bağımlı olması yani bir sınıfın 
  çalışması için başka bir sınıfa ihtiyaç duymasıdır diye açıklayabiliriz Yandaki 
  şekilde gördüğümüz gibi üst seviyeli bir katman alt seviyeli katmanı (sınıfları,arayüzler... 
  olabilir ) kullandığı için burada üst seviyeli katmanımız alt seviyeli 
  katmana bağımlı diyebiliriz. Tekrar kullanılabilirlik terimine gelince; 
   ilk olarak bir sınıfın yazılıp projenin çeşitli yerlerinde kullanılması 
  aklımıza gelir fakat gerçek anlamda tekrar kullanım yazdığımız bir kod, 
  üst seviyeli bir kütüphane diğer projelerde koduna dokunulmadan kullanılabiliyosa 
  bunu tekrar kullanılabilir modül ya da yazılım olarak tanımlayabiliriz. 
  Bunuda iyi tasarlanmamış yazılımlarda sınıfların birbirine olan bağımlılığı 
  yüzünden genellikle yapamayız.
 
 İşte bu noktada 
  daha esnek ve yeniden kullanılabilir modüller geliştirebilmek için uygulanması 
  gereken önemli bir yazılım prensibi olan Dependency Inversion Principle(DIP)(Bağımlılığın 
  Ters çevrilmesi) devreye giriyor. Bu yöntemi kısaca açıklarsak;
 
 Üst 
  seviyeli modüller,sınıflar vb.. alt seviyeli sınıflar, modüllere bağımlı olmamalıdır. 
  Alt seviyeli modüller üst seviyeli modüllere(modüllerin arayüzlerine) bağımlı 
  olmalıdır. Buna kısaca Dependency Inversion (bağımlılığın ters çevrilmesi) deriz.
 
 Bunu da şekilde 
  gördüğümüz gibi üst seviyeli bir modül kendi arayüzünü tanımlayarak bu arayüzü 
  kullanır. Bu arayüz abstract ya da interface sınıflar olabilir. Ardından alt 
  seviyeli modüller üst seviyeli modülün arayüzünü uygular. Böylece üst seviyeli 
  modülümüz alt seviyeli detaylarla ilgilenmeden onlardanki değişimlerden etkilenmeden 
  kullanılabilir. Üst seviyeli modülümüz bir arayüze bağımlı olduğu için ve arayüzde 
  genellikle değişmeyeceği için arayüzü gerçekleyen (implemention) sınıflar 
  değişse dahi aynı kalacaktır. Günümüzdeki frameworklerin tasarlanmasında kullanılan 
  temel prensiplerden biri budur.
 
 Bu kadar laf kalabalığından 
  sonra biraz sıkılmış olabilirsiniz.Ufak bir örnekle sıkıntınızı alıp işe koyulalım:) 
  Örnek senaryomuz şöyle olsun:
 
 Geliştirdiğimiz 
  bir yazılımda işyerimizle alakalı kayıtları işliyoruz. Programımızın işyerindeki 
  çalışanlara ait çeşitli formatlarda rapor sunması gerekiyor. Şuanda bizden istenen 
  excel ve word formatından raporları sunması. Fakat ileride değişik türden formatta raporlarıda 
  kolaylıkla sunması kesinlikle istenecektir. Unutmayın müşteri istekleri 
  bitmez:) Bu işlemleri yaptığımız bir çalışan raporları sayfamız var. Bu 
  sayfadan herhangi bir çalışanı seçip onla alakalı çeşitli formattaki raporları 
  alabiliyoruz. Bu isteklere göre tasarladığımız sınıflarımızın UML diyagramını 
  aşağıda görebiliriz.
 
 
   
 Yukarıdaki şekilde de gördüğümüz gibi Calisan rapor forumumuz CalisanRaporFormu 
  sınıfı üst seviliyeli bir işi yapan sınıftır. CalisanWordRaporu ve CalisanExcelRaporu 
  ise bu üst seviyeli işlemin nasıl yapılacağını değişik şekillerde uygulayan 
  alt seviyeli detaylarla ilgilenen sınıflardır. CalisanRaporFormu bu sınıfları 
  direkt olarak kullanır. Yani CalisanRaporFormu sınıfı alt seviyeli sınıflara 
  direk olarak bağımlıdır onlarda meydana gelecek değişimlerden etkilenecek ve 
  tekrar derlenmek zorunda kalacaktır. Bu şekilde tasarlanmış yazılımlığımızın 
  kodları kabaca aşağıdaki gibi olur. Kodlara baktığımızda ilk olarak if else 
  yapısı dikkatinizi çekmiştir. Genellikle kodunuzda buna benzer kısımları görürseniz 
  büyük ihtimalle refactoring(yeniden biçimlendirme) yapmanızda fayda vardır. 
  İyi şekilde tasarlanmış yazılımlarda genellikle if-else ve switch-case cümleleri 
  kodun içinde fazla bulunmaz. Bunu da aklımızda bulundurmamızda fayda var. Aşağıda 
  buna örnek bir dizi sınıf tasarımı verilmiştir.
 
 
 
   
    | public class 
      CalisanRaporFormu { private List calisanlar;
 private Calisan seciliCalisan;
 private CalisanWordRaporu 
      wordRaporu =new CalisanWordRaporu();
 private CalisanExcelRaporu 
      excelRaporu =new CalisanExcelRaporu();
 
 public CalisanRaporFormu(){ }
 
 public void SeciliCalisanaAitRapor()
 {
 if(raporTipi=="Word")
 wordRaporu.RaporOlustur(seciliCalisan);
 else 
      if(raporTipi=="Word")
 excelRaporu.RaporOlustur(seciliCalisan);
 }
 }
 |  
 
   
    | public class 
      Calisan { private string adi;
 private int maas;
 private string soyadi;
 private int mesaiSaati;
 public Sirket m_Sirket;
 
 public Calisan(){ }
 
 public int MesaiUcretiHesapla(){ 
      }           public 
        string adi{
 get{return 
        adi;}
 set{adi 
        = value;}
 }
 
 public int maas{
 get{return 
        maas;}
 set{maas 
        = value;
 }
 }
 ....
 }
 
 
 |  
 
   
    | public class 
      CalisanWordRaporu { public CalisanWordRaporu(){  
             }
 
 public void RaporOlustur(Calisan 
        calisan){
 //raporlama 
        ile alakalı kodlar....
 }
 }
 
 public class CalisanExcelRaporu {
 public CalisanExcelRaporu(){
 
 }
 
 public void RaporOlustur(Calisan 
        calisan){
 //raporlama 
        ile alakalı kodlar....
 }
 }
 
 
 |  Yukarıdaki kodlar senoryamuzdaki bizden istenenleri gerçekleştiriyor. Müşterimide 
yazılımı teslim ettik herşey gayet güzel çalışıyor. Fakat beklenen kara gün geldi 
müşteri yeni isteklerle karşımıza çıktı:) Bunlardan senaryomuzda biraz da olsa 
bahsetmiştik.Bunlardan birtanesi senaryomuzda bizden istenen değişik formatta 
rapor çıktısı sunmasıydı ve müşteri bizden Pdf formatındaki raporları da sisteme 
eklememizi söyledi. Fakat bundan sonra yapılacak değişimler için önümüze birkaç 
problem çıkıyor. Yeni bir çalışan rapor formatını sisteme nasıl ekleriz? Bunun 
için eski kodlarımızın içini didiklemeye başladık ve bu işlemin CalisanRaporFormu 
sınıfı içinde yapıldığını gördük. Hemen kolları sıvadık başladık yeni rapor formatını 
sistemimize eklemeye.Sonra bütün kodlarımızı tekrar derleyip yeni halini müşterimize 
gönderdik.Değişin CalisanRaporFormu sınıfımız ve yeni eklenen Pdf raporu sınıfımız 
aşağıdaki şekilde olacaktır.
 
 
 
   
    | public class 
      CalisanRaporFormu { private List calisanlar;
 private Calisan seciliCalisan;
 private CalisanWordRaporu 
      wordRaporu =new CalisanWordRaporu();
 private CalisanExcelRaporu 
      excelRaporu =new CalisanExcelRaporu();
 
 private CalisanPdfRaporu 
      pdfRaporu =new CalisanPdfRaporu();
 
 public CalisanRaporFormu(){ }
 
 public void SeciliCalisanaAitRapor()
 {
 if(raporTipi=="Word")
 wordRaporu.RaporOlustur(seciliCalisan);
 else 
      if(raporTipi=="Word")
 excelRaporu.RaporOlustur(seciliCalisan);
 else 
      if(raporTipi=="Pdf")
 pdfRaporu.RaporOlustur(seciliCalisan);
 }
 }
 |  
 
  Yukarıda gördüğümüz 
  gibi ufak bir değişiklik sistemin birçok yerinde değişiklik yapmamızı mecbur 
  kılıyor ve bütün projeyi derleyip tekrar yayınlamamızı gerektiriyor. Kaldı ki 
  müşterinin istekleri hiç bitmeyeceği için:) her yeni rapor formatında ya da 
  programın değişik yerlerinde bu şekilde istekler için tekrar aynı işlemleri 
  yapmak zorunda kalacağız en azından yukarıdaki gibi if-else cümleleri kodumuzu 
  istila edecek bu da yazılımın yönetimini, yayınlanmasını, değişiklik eklemeyi 
  ve yeniden kullanımız zorlaştıracak. 
    | public class 
      CalisanPdfRaporu { public CalisanPdfRaporu(){   
              }
 
 public void RaporOlustur(Calisan 
        calisan){
 //raporlama 
        ile alakalı kodlar....
 }
 }
 
 
 
 |  
 Sistemimizi birde 
  Dependency Inversion prensibine göre baştan tasarlayalım ve ardından bize sağladığı 
  avantajlara bakalalım. Bunu yapmak için baştada bahsettiğimiz gibi bağımlılığı 
  ters çevireceğiz. Yani CalisanRaporFormu sınıfımız alt raporlama sınıflarına 
  bağımlı olmayacak kendi arayüzünü tanımlayacak ve yapacağı işlemlerde onu kullanacak. 
  Ardından alt seviye sınıflar bu arayüzü uygulayarak CalisanRaporFormu sınıfımızın 
  arayüzüne bağımlı olacak. Yeniden tasarlanmış sınıflarımızın UML diyagramı ve 
  kodları aşağıdaki gibi olur.
 
 
 
  
 
 
   
    | public class 
      CalisanPdfRaporu : ICalisanRaporu{ public CalisanPdfRaporu(){   
              }
 
 public void RaporOlustur(Calisan 
        calisan){
 //raporlama 
        ile alakalı kodlar....
 }
 }
 
 public class CalisanExcelRaporu : ICalisanRaporu{
 public CalisanExcelRaporu(){
 
 }
 
 public void RaporOlustur(Calisan 
        calisan){
 //raporlama 
        ile alakalı kodlar....
 }
 }
 
 public class CalisanWordRaporu : ICalisanRaporu{
 public CalisanWordRaporu(){
 
 }
 
 public void RaporOlustur(Calisan 
        calisan){
 //raporlama 
        ile alakalı kodlar....
 }
 }
 
 
 
 |  
 
   
    | public 
        class CalisanRaporFormu { private List calisanlar;
 private Calisan seciliCalisan;
 private ICalisanRaporu 
        calisanRaporu;
 
 public CalisanRaporFormu(ICalisanRaporu 
        calisanRaporu)
 {
 this.calisanRaporu 
        = calisanRaporu;
 }
 
 public void SeciliCalisanaAitRapor()
 {
 this.calisanRaporu.RaporOlustur(seciliCalisan);
 }
 }
 
 
 
 |  Yukarıda yeni şekilde tasarladığımız kodlarda da gördüğümüz gibi artık üst seviyeli 
bir sınıfımız olan CalisanRaporFormu sınıfımız alt seviyeli sınıflardan olan CalisanPdfRaporu 
vb.. sınıflara bağımlı değildir, sadece kendi arayüzünü tanımlamış ve işlemlerinde 
bu arayüzü kullanmıştır. Alt seviyeli sınıflar ise CalisanRaporFormu arayüzü olan 
 ICalisanRaporu arayüzünü CalisanRaporFormu sınıfına, 
onun kullandığı arayüze bağımlı olmuşlardır. Bu şekilde bağımlılığı ters çevirmiş 
olduk.Yukarıdaki kodları gördüğünüzde aklınıza CalisanRaporFormu sınıfının hangi 
rapor formatı ile çalışacağını nerden bileceği gelebilir. Bunu gördüğünüz gibi 
CalisanRaporFormu yapıcısında hangi rapor formatı ile çalıştığını alıyor. Genelde 
bu tür işlemler herbiri ayrı bir makale konusu olan Factory Tasarım 
Kalıbı ve Inversion Of Control (IoC) denilen 
tekniklerle yapılır. Şuanda kafanız o kısımda karışmasın diye deyinmek istemedim 
ayrı bir makalede bu konulara deyinmeye çalışacağım. 
Yeni şekilde tasarlanan kodun avantajlarına bakarsak gördüğümüz 
  gibi CalisanRaporFormu artık kendi arayüzü uygulayan hangi tür rapor olursa 
  olsun kod içinde hiçbir değişiklik yapmadan kullanabileceğiz. Tabi kodun içindeki 
  if-else ifadeleri kalktığı için kodunda sadeleştiğini görüyoruz. Ayrıca bundan 
  sonraki yeni rapor türleri için CalisanRaporFormu sınıfını tekrar derlemek zorunda 
  değiliz çünkü bu sınıf ICalisanRaporu arayüzünü kullanıyor 
  ve bu arayüz değişmedikçe tekrar dermemize gerek kalmayacak. Müşteriye sadece 
  yeni eklediğimiz rapor formatı sınıflarını vermemiz yeterli olacaktır. Artık 
  CalisanRaporFormu bizim için ayrı bir modül oldu. Değişik projelerde onun arayüzünü 
  uygulayan herhangi bir sınıfla rahatlıkla çalışabilir. Tabi onu kütüphane yapıp 
  aynı namespace içine ICalisanRaporu arayüzünüde eklemeyi unutmayalım. Paket 
  yapımızda aşağıdaki gibi olur. Artık müşteride bulunan CalisanRaporu paketi(kütüphane,dll) 
  yeni rapor formatı ekleme işlemleri için değişmeyecektir. Sadece RaporFormarlari 
  paketine yeni rapor formatını ekleyerek tekrar derleyip müşteriye vermemiz yeterli 
  olacaktır.
 
 
  
 Gördüğünüz gibi ufak bir örnekle de olsa önemli bir tasarım prensibinin bize 
  sağladığı avantajları oldukça önemli. Yeniden kullanılabilir modüller ve frameworkler 
  tasarlamanın temel prensiplerinden biri olan bu tasarım prenbini ufak bir örnekler 
  inceledik umarım sizler için faydalı olmuştur. Tekrar görüşmek dileğiyle...
 
 
 
                Makale:Dependency Inversion Principle (DIP) C#, Visual C# ve .NET Cihat Altuntaş
 | 
        
            |  | 
        
            |  | 
        
            | 
                    
                        
                            
                        
                            Eklenen Son 10 
                            Bu Konuda Geçmiş 10 
                        
                            Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
                         
                            Son Eklenen 10 Makale Yükleniyor
                         
                            Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
                         | 
        
            |  |