Application Repository Ninject Modülü

29 May

Bu yazımızda, veri merkezli(data centric) uygulamalarda alışılagelmiş bir yöntem olan Repository kullanımının, birden fazla veri kaynağının bulunduğu durumlarda nasıl yapılması gerektiği konusunu incelemeye çalışacağız.

Repository mantığında öncelikle tüm alt sınıfları hiyerarşik bir düzene sokmak adına tanımlanan bir interface vardır. Örnek olarak basit bir interface tanımlamasını şu şekilde ifade ediyor olalım.


public interface IRepository<T>
{
    void Add(T entity);
    IList<T> GetAll();
}

Bu interface altında veritabanına ekleme ve veritabanından veri getirme gibi iki temel işlem vardır. Eğer bir SQL veri tabanına veri yazmayı amaçlıyorsak bu işlemi gerçekleştiren somut sınıfın oluşturulması gerekmektedir.


 public class SqlRepository<T> : IRepository<T>
 {
   public void Add(T entity)
   {
       // Veritabanına ekle..
   }

   public IList<T> GetAll()
   {
       // Veritananından oku..
   }
 }

Buraya kadar işler normal akışında seyrediyor. Ancak SQL veri tabanına yazılamadığı durumlarda ne olacağı bir soru işareti. Ya da başka bir sebepten dolayı ilişkisel veri tabanına yazmak yerine kayıtları XML bir dosyaya yazmak gerektiğinde XML dosya ile çalışabilen somut bir repository oluşturulması gerekmektedir. Bu durumda yeni bir sınıfa ihtiyaç duyulmaktadır.


 public class XmlRepository<T> : IRepository<T>
 {
    public void Add(T entity)
    {
       // XML dosyaya ekle...
    }

    public IList<T> GetAll()
    {
       // XML dosyadan oku...
    }
 }

Ancak bu iki farklı Repository tipinin, çalışma zamanında seçilebilir ve değiştirilebilir olması gerekmektedir. Aksi taktirde kodun değiştirilebilir olması istenmeyen bir durumdur. Bu değişime ayak uydurabilmek adına, değişikliği otomatik olarak gerçekleştirebilecek bir sınıfa ihtiyaç duyulmaktadır. Bu sınıf, çalışma zamanında dependency injection mekanizması ile yüklenebilen bir modül halinde tasarlanabilir.


 public class ApplicationRepositorySelectionModule : NinjectModule
 {
    public override void Load()
    {
        switch (ApplicationConfiguration.StorageType)
        {
           case PersistenceStorageType.SqlRepository:
              Bind(typeof(IRepository<>)).To(typeof(SqlRepository<>));
              break;
          case PersistenceStorageType.XmlRepository:
              Bind(typeof(IRepository<>)).To(typeof(SqlRepository<>));
              break;
         default:
              throw new ApplicationException("Not supported storage type!");

       }
    }
 }

NinjectModule sınıfı, Ninject dependenjy injector aracına ait bir sınıftır. Yaptığı işlem ise  Interface türlerine karşılık hangi somut sınıfın oluşturulacağını belirlemektir. Zamanı geldiğinde ilgili nesneyi oluşturup programa sağlamak yine Ninject tarafından gerçekleştirilmektedir.

Modül içerisinde kullanılan PersistenceStorageType ve ApplicationConfiguration sınıfları ise şu şekildedir.


 public class ApplicationConfiguration
 {
     public static PersistenceStorageType StorageType { get; set; }
 }

 public enum PersistenceStorageType
 {
     SqlRepository = 0,
     XmlRepository = 1
 }

Bu şekilde birden fazla repository sınıfı ile konfigurasyonu sağlababilir şekilde çalışmak mümkün olmaktadır. Yazılımda çevikliği yani yazılımın değişime ayak uydurabilme yeteneğini sağlayabilmek açısından uygulanabilecek olan küçük bir detaydan bahsetmiş olduk.

Bir sonraki yazıda görüşmek dileğiyle.

Bir İki Cümleyle Design Patterns

17 Eyl

Factory Pattern
Nesne oluşturma işleminin bir iş kuralı dahilinde olduğu durumlarda kullanıcıyı kuralın dışında tutarak nesne oluşturmak için kullanılır. Kurallara uygun bir şekilde soyut tipleri implemente eden  somut nesneler oluşturularak kullanıcılara verilir.

Abstract Factory Design Pattern
Factory nesneleri oluşturmak için kullanılan bir desendir. Yani Abstract Factory deseni ile soyut bir factory nesnesi oluşturulur, bu factory nesnesinden de belirlenen kural dahilinde bir nesne oluşturulur. Küme alt küme mantığına benzer bir yapı söz konusudur.

Adapter Design Pattern
Birbiriyle uyumsuz iki farklı interface arasında anlaşma sağlayan bir köprü vazifesi görür. Bunu gerçek hayatta cep telefonu ile elektrik prizi arasında görev yapan şarj aletine benzetebiliriz.

Template Pattern
Bir algoritma için soyut tipte bir iskelet oluşturarak bu iskeletten somut süreç adımları oluşturmamızı sağlar. Algoritmanın adımlarını somut sınıflarda tanımlarız. İskelet görevi gören tip bir şablon niteliğindedir.

Singleton Design Pattern
Bir sınıfa ait sadece tek bir nesne oluşturmayı ve gerektiğinde ona ulaşabilmeyi garanti eder. Yani nesne oluşturma üzerine oluşturulmuş bir desendir.

Decorator Pattern
Nesnelere kompozisyon yoluyla yeni davranışlar eklememizi sağlar. Bu işlemi aynı temel sınıftan türeterek veya ortak bir interface uygulayıp nesneye enjekte ederek yapabilmek mümkündür.

State Pattern
Bir nesnenin iç durumunda meydana gelen değişikliklerin nesnenin davranışını değiştirmesine izin verir. İç durumdan kasıt interface tipleridir.

Strategy Pattern
Çalışma zamanında dinamik olarak algoritma değişikliğine olanak sağlayan bir desendir. Algoritmalar somut nesnelerde saklanır. Client kod ise algoritma sınıfının türetildiği abstract veya interface türünü tanır.

  • Not: State ve Strategy pattern diyagram olarak birbirine benzerdir. Ancak çalışma prensipleri açısından birbirlerinden farklıdırlar. State pattern için nesnenin NE olduğu önemlidir. Strategy için nesnenin NASIL çalıştığı önemlidir.

Specification Pattern
İş nesneleri içerisinde gömülü olan seçim kriterlerini başka nesneler ile paylaşamazsınız veya tekrar tekrar kullanamazsınız. Specification pettern, bu problemi ortadan kaldırır.

Composite Pattern
Nesnelere ağaç yapısında ya da hiyerarşik topluluklar halinde gruplanabilme yeteneği sunar. Örneğin bir kategorinin alt kategorisi olabileceği gibi onun da alt kategorisi olabilir.

Proxy Design Pattern
Bir sınıfın işlevselliği başka bir sınıf ile temsil edilir. Cache mekanizmaları oluşturulurken kaynak kullanımını azaltmak için kullanılabilir. Örneğin veri tabanından veri getiren bir nesne, aynı verilere ihtiyaç duyulduğunda tekrar veri tabanına gitmeye gerek duyulmadan kullanılabilir.

Builder Design Pattern
Kuramsal bir iş akışını işletmek için gerekli olan kompleks bir nesnenin basit nesneler ile adım adım oluşturulmasına olanak sağlar.

Kitap – Head First Design Patterns

21 Ağu
Head First Design Patterns
Head First Design Patterns

Kitaplar serisine ait bu yazıda Hear First Design Patterns isimli kitabı incelemeye çalışacağız. Kitabın yazarları Eric Freeman ve Elisabeth Freeman‘dır. O’REILLY yayınlarından çıkmıştır. Amazon üzerinden bu kitaba ulaşabilirsiniz.

Kitap 638 sayfa olup dili İngilizcedir. İngilizce seviyesi ortanın üstünde olmayanlara bu kitabı önermem.

Head First Design Patterns tasarım şablonlarını nesneye yönelik programlama teknikleri ile harmanlayarak işlemiştir. Anlatımı gayet akıcıdır ve anlaşılması kolaydır. Konuları düz metin ağırlıklı değil, resimlerle ve şekillerle güçlendirerek görsellik üzerinde anlatımını yoğunlaştırmıştır. Bu sayede konuların kolay anlaşılması sağlanmıştır.

Bu kitabı okurken Java bilgisine sahip olmanız gerekir. Örnekler Java programlama dili ile geliştirilmiştir. Ancak C# programlama dilini bilenlerin de okuyabileceği bir kitaptır. Java veya C# dillerinde uzmanlaşmış olmanıza gerek yoktur, nesneye yönelimli programlama tekniklerini bilmeniz yeterlidir.

Kitabı okurken hiç sıkılmadım. Örnekler gayet sade ve anlaşılır geldi bana. Tasarım şablonlarını öğrenmek ve uygulamak isteyenlere kesinlikle öneririm. Tabi ki bu kitap sihirli bir değnek değil. Okuyan herkes tasarım şablonlarının en iyi uygulayıcısı olacak diye bir kaide koymuyorum. Kitaptan aldıklarını kendi problemlerinize uygulamak size kalmış. Umarım faydalı olur. Tekrar görüşmek dileğiyle.

Adapter Tasarım Deseni (Design Pattern)

1 May

Adapter tasarım deseni, kodun bağımlılığını azaltmak amacıyla uygulanan kalıplardan biridir. Özellikle kurumsal bazlı projelerde modüler yapıda geliştirme yapıldığı düşünüldüğünde uyumluluğun sağlanması, gerekli şartlardan saedce biridir. Proje üzerinde çalışan geliştiriciler farklı modülleri hazırlayıp ortak bir noktada yazılıma monte edebilmelidir.

Adapter Tasarım Deseni
Adapter Tasarım Deseni

Yukarıdaki şemada “Client” tarafındaki kod biriminin soyut olan (interface veya abstract) “Target” kod birimini tanıması ve “Target” tipinden türetilen diğer tipleri tanımaması modülerliğin ve test edilebilirliğin sağlanabilmesi için gerekli esnekliği bize sunmaktadır. “Adapter” tarafındaki kod birimleri, “Target” tipinden türetilmektedir. Bu noktadaki implementasyonları N sayıda geliştirici yapabilmelidir.

Adapter Tasarım Örnek
Adapter Tasarım Örnek

Bu şemada “Client” kod olarak bir rapor servisi (ReportService) sunulmaktadır. ReportService Servis tipimiz sadece soyut olan “IReportProducer” tipini tanır. IReportService tipinin uygulandığı WordReportAdapter tipini tanımaz. WordReportAdapter tipi sadece Microsoft.Office kütüphanesini kullanarak Word dökümanı üretir.

İki farklı geliştirici olduğunu düşünecek olursak birine Word dökümanı üreten adaptörü, diğerine de PDF dökümanı üreten adaptörü yazdırabiliriz. Geliştiricilerimiz de ReportService tipiyle ilgilenmezler. Sadece IreportProducer tipini tanırlar ve bu tipi implemente ederek PDF ve Word raporu üreten sınıfları geliştirirler.

Örnek uygulama

Örnek uygulama olarak yukardaki şemanın C# kodu ile yazılmasını ele alabiliriz.

public interface IReportProducer
{
    void CreateReport(Report report);
}
public class ReportService
{
      private readonly IReportProducer reportProducer;
      public ReportService(IReportProducer reportProducer)

          this.reportProducer = reportProducer;
      }
     public void CreateReport()
      {
          reportProducer.CreateReport(new Report());
      }
}
public class WordReportAdapter : IReportProducer
{
      public void CreateReport(Report report)
      {
          // TR: Office DLL nesneleri yardımıyla raporu oluştur.
          // EN: Get Office DLL objects and create Report
      }
}

Bu tasarım sayesinde ReportService sınıfı test edilebilir hale getirilmiş oldu. Mock nesneler oluşturulup tast işlemini gerçekleştirmek basitleşti.

Eğer Word döküman raporunu üreten kodu ReportService sınıfı içerisinde yapsaydık;

  • Test edilebilirlikten uzaklaşacaktık.
  • Birden fazla developer ile bir işi geliştiremeyecektik.
  • Rapor servis tipi somut nesnelere bağımlı olacaktı.
  • Yeni bir rapor üretici geliştirilmek istediğimizde servis sınıfını bozmak zorunda kalacaktık.

Adapter tasarım kalıbının uygulanması gayet basittir. Tek amacı ise birbirini tanımayan tipleri interface gibi soyut tipler kullanarak birbiri ile çalışabilir hale getimektir.

Kaynak Kod: https://skydrive.live.com/redir?resid=2884CE0681105B31!147

Specification Pattern (Şartname Tasarım Kalıbı)

3 Nis

Specification tasarım kalıbı, bir nesne içerisindeki mantıksal (boolean) yapıdaki iş kurallarının, dışarıdan almasını sağlamak amacıyla oluşturulmuştur. İş kuralları, birbirini takip eden zincirli bir yapıda olup daha karmaşık bir iş kuralını da ortaya çıkarabilir.

Kod Örneği

Desenin anlaşılabilmesi açısından bir kod örneği ile devam etmek istiyorum. Kod örneğimizi bir iş nesnesi üzerindeki mantıksal kuralları ele alarak geliştirmeye çalışacağız. Örneğimizde bir ürünü temsil eden tip üzerinden ilerleyeceğiz.

Ürün tipinde, stok durumunun yeterli olup olmadığını belirleyen bir mantıksal iş kuralını dışarıdan temin edecek şekilde modelleyerek ilerleyelim.

Altyapımızı oluştururken öncelikle şartname niteliğinde bir interface hazırlamalıyız.

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T candidate);
}

Şartnamemizde, bu şartnameyi uygulayan sınıfların tipinden bir generic “T” parametresi verilmiştir. Bu sayede şartname tipi dışarıdan alınabilir şekilde genelleştirilmiştir.

ISpecification<T> tipine T parametresi yerine vereceğimiz ve iş nesnesi olarak kullanacağımız ürün tipini, adını Product olacak şekilde belirliyoruz.

public partial class Product
{
    public decimal Stock {get; set; }
}

Artık bu tipimize bir iş kuralı belirlememiz gerekmektedir. İş kuralımızı kısaca stok miktarının kritik olduğu durumu gözetecek şeklide belirleyebiliriz. Stok miktarı 50’nin altına düşerse şartımız çalışacaktır.

public class IsCriticalStock : ISpecification<Product>
{
     public bool IsSatisfiedBy(Product product)
     {
         return candidate.Stock < 50;
     }
}

Şartnameyi kabul eden bir tip olarak IsCriticalStok isimli sınıf oluşturduk. Artık iş kuralını bünyesinde barındıran bu sınıfımızı Product tipine tanıtabiliriz. Product tipimizi yeniden tasarlayacak olursak;

public partial class Product
{
       private readonly IsCriticalStock isCriticalStock;

       public Product()
       {
           isCriticalStock= new IsCriticalStock();
       }

       public decimal Stock {get; set; }

       public bool IsStockEnough()
       {
            return isCriticalStock.IsSatisfiedBy(this);
       }
}

Bu şekilde iş kuralımızı Product tipine geçirmiş oluruz. Kodun okunabilirliğini arttırmak için Product sınıfını parçalı şeklide “Partial” tanımlayabiliriz.

public partial class Product
{
      private readonly IsCriticalStock isCriticalStock;

      public Product()
      {
          isCriticalStock= new IsCriticalStock();
      }

      public decimal Stock {get; set; }
}

public partial class Product
{
      public bool IsStockEnough()
      {
        return isCriticalStock.IsSatisfiedBy(this);
      }
}

Bu örnek aracılığıyla Specification tasarım kalıbını en basit haliyle incelmiş olduk.

Abstract Factory Method Tasarım Deseni

20 Mar

Factory Method tasarım deseni, nesne oluşturma ihtiyacı doğrultusunda ortaya çıkmış bir tasarım desenidir. Bu tasarım deseni, oluşturulacak somut nesnenin türünü belirlemeye gerek duymadan nesne oluşturma işlemini temel almaktadır.

Resim-1
Resim-1

Factory deseninin temel amacı nesne oluşturma karmaşıklığını kullanıcıdan gizlemektir. Ayrıca kullanıcı, oluşturulacak nesnenin somut türünü belirlemek zorunda değildir. Bunun yerine somut nesnenin implemente edildiği soyut tür olan interface veya abstract class tipini bilmesi yeterlidir. Yani sorumluluk somut nesnelerden soyut nesnelere aktarılmaktadır. Genel olarak Factory sınıflar “static” erişim belirleyicili bir metod barındırırlar. Bu metod, kullanıcıya interface veya abstract class tipinde bir nesne döndürür. Bu sayede kullanıcılar, alt sınıfların oluşturulması sorumluluğundan dolayı oluşabilecek hatalardan da uzak tutulmuş olur.

Örnek Uygulama

Bu örnek uygulamamızda Grafik türüne göre Grafiğin temsilini yapan Sembollerin oluşturulmasını Factory Method yöntemiyle üretmeyi amaçlamaktayız.

Yukarıdaki şekildeki tasarım deseninin uygulanışını şu şeklide yapabiliriz.

Resim - 2
Resim – 2

Gerçek bir uygulamadan alarak göstereceğim bu örnekte bir REST servisinden gelen Graphic nesnesinin türüne göre sembol nesnesinin belirlenmesi işlemini Factory Method inceleyeceğiz. Tabi bu örnekteki konumuz Factory uygulaması olduğundan Servis işlemlerini temsili olarak göreceğiz. Bizi ilgilendiren sadece nesne üretimi olduğundan nesne üretim aşamasını inceleyeceğiz.

   public class Graphic
   {
      public Symbol Symbol { get; set; }
   }

Bize servis tarafından sunulan Graphic nesnesi Null olarak gelmektedir. Biz yazılım tarafında Graphic nesnesinin türüne göre Sembolünü üretmekle sorumluyuz.

public abstract class Symbol
{
     public abstract void draw();
}

Symbol sınıfının soyut bir tip olduğunu görüyoruz. Graphic sınıfında da bu soyut tip kullanılmıştır.

public class SimpleLineSymbol: Symbol
{
    public override void draw()
    {
       // Draw line
    }
}

public class SimpleFillSymbol: Symbol
{
     public override void draw()
     {
       // Draw polygon
     }
}

public class SimpleMarkerSymbol: Symbol
{
    public override void draw()
    {
       // Draw point
    }
}

Somut sembol sınıfları ise SimpleLineSymbol, SimpleFillSymbol, SimpleMarkerSymbol şeklinde oluşturulmuştur.

public class GraphicSymbolFactory
{
    public static Symbol GetSymbol(Graphic graphic)
    {
        if(graphic is Point)
           return new SimpleMarkerSymbol();
        if(graphic is Polygon)
           return new SimpleFillSymbol();
        if(graphic is Polyline)
           return new SimpleLineSymbol();

        throw new InvalidExpressionException("Unknown graphic type");
    }

}

GraphicSymbolFactory sınıfına eklediğimiz GetSymbol metodu, Graphic türüne göre somut olan Symbol tiplerini oluşturmaktadır. Dikkat edecek olursak kullanıcıya soyut olan bir Symbol tipi vermekteyiz. Yani içerde olup bitenden kullanıcılar haberdar değildir.

public class GraphicService
{
    private readonly IGraphicRestService service;

    public GraphicService(IGraphicRestService service)
    {
       this.service = service;
    }

    public Graphic GetGraphicsFromRESTService(string serviceUrl)
    {
       Graphic graphic = service.GetGraphic(serviceUrl);

       graphic.Symbol = GraphicSymbolFactory.GetSymbol(graphic);

       return graphic;
    }

}

GraphicService sınıfı içerisinde tanımlı GetGraphicsFromRESTService metodu, bir servis yardımıyla Graphic nesnesini elde etmektedir. Gelen Graphic nesnesinin sembolü ise kullanıcı tarafından Factory sınıfı yardımıyla belirlenir. Burada kullanıcı diye adlandırdığımız GraphicService sınıfıdır aslında. Çünkü API içerisinde hazırladığımız GraphicSymbolFactory tipini kullanan sınıftır. Kullanıcı sınıf aslında Symbol tipinden türetilen SimpleLineSymbol veya SimpleFillSymbol gibi tiplerden haberdar değildir. Bu somut tipleri oluşturmak zorunda da değildir. Bu karmaşık sorumluluğu Factory deseni ile bir sınıfa aktarmış olduk.

Bir başka yazıda görüşmek dileğiyle.

Dependency Injection Tasarım Deseni

4 Nis

Yazılım dünyasında ürünlerden daha çok prensiplere ve ilkelere önem verenlerdenim. Java veya C# dilinde yazmışım çokta dert değil benim için. Bir dilin yazım kurallarını ve ürün geliştirme araçlarını öğrenmek çokta uzun zaman almaz. Yazılım geliştirdiğimiz ortamların (IDE) pratiklerini anlamak çok önemlidir elbette. Ama yazılım prensipleri ve ilkelerini benimsemek, o ilkelere sadık kalarak yazılım geliştirmek bana göre daha önemlidir. Bu yazımızda da yazılım geliştiricilerin zamanla edindiği tecrübelereden biri olan Dependency Injection tasarım deseni üzerinde duracağız.

Resimde ne görüyorsunuz diye bir soru sorsam, süpheli süpheli bakmaya mı başlarsınız, yoksa USB anahtarlıklar ve iki anahtar mı dersiniz bilmiyorum. Ama sistematik bir görüntü var aslında resimde. Canı isteyen sistemdeki anahtarlıkları halkadan boşandırıp değiştirebilir. Çünkü halka esnek bir yapıda yani birbirine sabitlenmemiş. Aynı şekilde isteyen, ipliğin ucundaki USB aygıtlarını da istediği renkle değiştirebilir. Çünkü iplikte basit bir düğüm, dolayısıyla anahtarlık ve anahtarlar arasında gevşek bir bağ mevcut. Aynı şekilde USB aygıtlarının kapakları da birbirine uyumlu olduklarından  istenen renkte anahtarlık veya kapak seçilebilir ve ikili oluşturulabilir. Bu durum sistemin esnek olduğunu ve tüm bileşenler arasında gevşek bir bağlantı söz konusu olduğunu göstermekdir.

Yazılım tasarım desenlerinde de sıklıkla karşılaştığım “gevşek bağlılık” deyiminin de ifade etmek istediği şey yukarıdaki şekilde anlatıldığı gibidir. Nesnelerin birbirine uyumlu ve birbirini etkilemeyecek şeklide olmasıdır.

Yazılım tasarım desenlerinden biri olan, Dependency Injection (Bağımlılıkların Dışarıdan Enjekte Edilmesi) deseni de bileşenlerin(components) birbirine olan sıkı bağlarının gevşetilmesini ve yazılımın test edilebilir bir hale getirilmesini amaçlamaktadır. Test edilebilir tasarım konusuna daha sonraki yazılarda değinmek istiyorum. Şu anda ilgileneceğimiz konu tasarımdaki gevşek bağlılık(Loosely Coupled) üzerinden ilerleyecektir.

Bir örnek uygulama üzerinden devam etmelim. Senaryomuz bir şirketin çalışanlarının aylık ve günlük satış istatistiklerini veren bir sınıfın tasarlanması şeklinde olacaktır.

public interface IEmployeeStatistics
{
       decimal GetDailySales(int employeeId);
       decimal GetMonthlySales(int employeeId);
}

Yukarıdaki arayüz(interface), diğer bir deyişle sözleşme, employeeId bilgisi verilen çalışanın günlük ve aylık satış tutarlarını verecek şekilde hazırlanmıştır.

Aşağıdaki EmployeeStatistics sınıfı ise IEmployeeStatistics arayüzünden türetilmiş sınıfların getireceği istatistikleri dış dünyaya sunmaktan sorumlu olacaktır.

public class EmployeeStatistics
{
       private IEmployeeStatistics employeeStatistics;

       public EmployeeStatistics(IEmployeeStatistics employeeStatistics)
       {
              this.employeeStatistics = employeeStatistics;
       }

       public decimal GiveMeDailyReports(int employeeId)
       {
              return employeeStatistics.GetDailySales(employeeId);
       }

       public decimal GiveMeMonthlyReports(int employeeId)
       {
              return employeeStatistics.GetMonthlySales(employeeId);
       }

}

EmployeeStatistics sınıfının kurucu metodundaki bağımlılık, IEmployeeStatistics arayüzü tarafından sağlanmıştır.

Dış dünyaya sunum yapan sınıf olan EmployeeStatistics sınıfı, eline gelen istatistiklerin hangi veritabanından kullandığını, hangi aşamalardan geçtiğini, ne zorluklar çektiğini bilmez. Hatta sınıfın adını bile bilmez. EmployeeStatistics sınıfı için önemli olan sadece constructor metoduna gelecek olan tipin IEmploeyeeStatistics arayüzünü uygulamış (implement) olmasıdır. Aynen yukardaki resimde anahtarlığa bağlanan USB anahtarlıkların ne şekilde olduğunun önemsiz olduğu gibi.

Şimdi de MSSQL veritabanından istatistik çeken sınıfı oluşturalım.

public class EmoleeStatisticsFromMSSQL : IEmployeeStatistics
{
       public decimal GetDailySales(int employeeId)
       {
              //.....
              //.....
              // MSSQ'den getirme işlemleri

              decimal result = 5214M;

              return result;
       }

       public decimal GetMonthlySales(int employeeId)
       {
              //.....
              //.....
              // MSSQ'den getirme işlemleri

              decimal result = 23514M;

              return result;
        }
}

Eğer EmployeeStatistics sınıfı içerisinde IEmployeeStatistics tipini değilde şu anda oluşturduğumuz EmployeeStatisticsFromMSSQL tipini direk kullansaydık iki sınıf arasında (EmployeeStatistics ve EmployeeStatisticsFromMSSQL) sıkı bir bağ oluşacaktı. Bu durumda, sistemde çalışma zamanında(runtime) EmployeeStatisticsFromMSSQL sınıfı yerine EmployeeStatisticsFromOracle gibi bir değişimi imkansız hale getirecekti. Ancak bu sıkı bağı IEmployeeStatistics arayüzü ortadan kaldırdı ve esnek bir bağ oluşturdu. Artık çalışma zamanında istenen sınıf devreye alınabilir. İstediğimiz sınıfı nasıl devreye alacağımız ise EmployeeStatistics sınıfına baktığımızda anlaşılabilmektedir. Sınıf içerisine Constructor seviyesinde bir enjeksiyon yapılmaktadır. Bağımlılıklar dışarıdan sınıf içerisine enjekte edilmektedir.

Bir süre sonra şirketiniz veritabanı yazılımını MSSQL yerine Oracle tarafına geçirmek istediğinde yapmamız gereken sadece EmployeeStatisticsFromOracle sınıfını oluşturmak olacaktır.

public class EmoleeStatisticsFromOracle : IEmployeeStatistics
 {
       public decimal GetDailySales(int employeeId)
       {
              //.....
              //.....
              // Oracle'dan getirme işlemleri

              decimal result = 5214M;

              return result;
       }

       public decimal GetMonthlySales(int employeeId)
       {
               //.....
               //.....
               // Oracle'dan getirme işlemleri

               decimal result = 23514M;

               return result;
       }

}

Bu sayede yazılımımız değiştirilmeye kapalı , geliştirilmeye açık hale gelmiş olacaktır. Yani yazılım prensiplerinden biri olan Open Closed (Gelişime açık değişime kapalı) prensibine de uygun hale gelmiştir.

Sınıfın kullanımı ise şu şekilde olacaktır.

public class Run
{
       public void Raporla()
       {
             IEmployeeStatistics reportProvider = getRaporUretici();

             EmployeeStatistics statistics = new EmployeeStatistics(reportProvider);

             var daily = statistics.GiveMeDailyReports(1);
             var monthly = statistics.GiveMeMonthlyReports(1);
       }

       private IEmployeeStatistics getRaporUretici()
       {
             //Web.config dosyasından hangi veritabanından çalışılacak, öğren.
             //"OR" ise Oracle, "MS" ise MSSQL

             var db = getDBFromConfig();

             IEmployeeStatistics reportProvider;

             if(db == "MS")
                 reportProvider = new EmoleeStatisticsFromMSSQL();
             if(db == "OR")
                 reportProvider = new EmoleeStatisticsFromOracle();
             else 
                 reportProvider = new NullStatistics();

             return reportProvider;
        }
}

Artık kodumuz değiştirilmeden geliştirilebilir haldedir. Yani config dosyasından belirlenen bir flag ile çalışan sisteme müdahale edilebilmektedir. Bu imkanı kolaylaştıran yöntem ise bağımlılıkların dışarıdan alınmasını sağlayan, Dependency Injection tasarım desenidir.

Kullanıma hazır bir yapıyı oluşturabildik. Tekrar görüşmek ümidiyle.