IoC Prensibi Nedir? Örnek Bir Proje ile Kullanımı ve Avantajları

IoC(Inversion Of Control), uygulamanın yaşam döngüsü boyunca birbirine bağımlılığı az (loose coupling) olan nesneler oluşturmayı amaçlayan bir yazılım geliştirme prensibidir. Nesnelerin yaşam döngüsünden sorumludur, yönetimini sağlar. IoC kullanan sınıfa bir interface inject edildiğinde, ilgili interface metotları kullanılabilir olur. Böylece IoC kullanan sınıf sadece kullanacağı metotları bilir, sınıf içerisinde daha fazla metot olsa bile interface’de belirtilen metotlara erişebilecektir.

Sınıf içerisinde yapılacak herhangi bir değişiklikte IoC kullanan sınıf etkilenmeyeceği için yeniden yazılabilir ve test edilebilir yazılım geliştirmemizi sağlar. IoC nesne bağlamalar genellikle uygulama başlangıcında yapılandırılmaktadır. Bu anlamda tek bir yerden yapılan IoC yapılandırmalarının değiştirilmesi ve yönetimi de oldukça kolaydır.

IoC kullanmanın avantajlarını şöyle sıralayabiliriz:

  • Loosely coupled (bağımlılığı az) sınıflar oluşturma
  • Kolay unit test yazma
  • Yönetilebilirlik
  • Modüler programlar
  • Farklı implementasyonlar arası kolay geçiş

Basit bir örnekle IoC prensibini bir projede nasıl uygulayabileceğimize bakalım. Örneği C# dilinde yapacağım ancak buradaki yaklaşım ve uygulanan kalıplar genel kullanımlar olduğu için çok benzer mantıkla farklı dillerde de IoC prensibi uygulanabilir.

.Net Core Web API projesi oluşturup birlikte adım adım ilerleyelim ve yukardaki diagramı takip edelim. API hizmetini 2 farklı database üzerinden verme opsiyonumuz olduğunu düşünelim.

1- Sıkı Bağlı Sınıflar (Tightly Coupled Class)

Veritabanı bağlantılarını yöneteceğimiz MsSQLConnection ve OracleConnection isimli 2 farklı sınıfa ihtiyacımız olacak.

Her iki sınıf da basit bir şekilde verinin hangi veritabanından geldiğini döndüren bir metoda sahipler.

ConnectionHelper sınıfı DAL katmanından veriyi okuyup controller’a vermekle görevli business logic işlevi gören sınıfımız olsun. (Burada farklı iş kuralları da yazılabilir)

Yukarda görüldüğü gibi iki sınıf arasında sıkı bir bağ bulunuyor. OracleConnection sınıfına referans verdik nesne örneği oluşturduk ve metodunu kullandık. Veriyi oracle’dan çektiğimizi görelim.

Burada kullandığımız sınıfı OracleConnection yerine MsSQLConnection olarak değiştirdiğimiz anda Helper sınıfı içerisinde(ve varsa başka sınıflarda) kullanıldığı tüm yerlerde de kodda manuel değişiklikler yapmak gerekecektir. Bu yüzden OracleConnection sınıfında yapılan değişiklikler helper sınıfımıza da yansıyacaktır. Temel problemimiz de aslında bu olacak.

2- Factory Pattern ile IoC İmplementasyonu

Bağımlılıkları azaltmak için adım adım örneğimizi ilerletiyorum. Bir factory sınıfı oluşturalım ve bir Connection örneği dönmesini sağlayalım. Client, Factory’den kendisine IConnection tipinde bir instance oluşturup vermesini ister, Factory bu nesneyi nasıl oluşturacağını bilir ve nesneyi Client’a döndürür.

Artık helper sınıfı Connection nesne örneğini dışarıdan alacak şekilde tasarlanmış oldu.

3- Abstraction Oluşturarak DIP İmplementasyonu

IConnection adında bir interface oluşturalım. İçerisine GetData metodunu ekleyelim, hatırlarsanız bu metot, örneğimizde sıkı bağlı sınıflar içerisinde kullanılıyor.

Oracle ve MsSQL sınıflarımız bu interface’i implement etsin.

ConnectionFactory sınıfı geriye somut bir nesne döndürüyorken bu interface sayesinde artık soyut nesne (IConnection) döndürecek.

Aşağıdaki şekilde IConnection interface’ini kullandığımız için ConnectionHelper’ın Oracle ve MsSQL sınıfları hakkında bilgi sahibi olmasını engellemiş olduk.

4- DI İmplementasyonu

Dependency Injection tasarım kalıbını kullanarak Connection’ı elde edelim. Inject etmek için property, metot ve constructor yolu ile olmak üzere 3 yöntem bulunmaktadır. Constructor yolu ile elde ederek devam edelim. Burada iki sınıf arasındaki bağı biraz daha gevşetmiş olduk.

Database kaynağımızı MsSQL’e çevirmek istiyorsak artık bunu Helper sınıfının nesnesinin oluştuğu yerde MsSQLConnection sınfını parametre olarak vererek yapmak gerekiyor.

Çalıştırdığımızda verinin MsSQL üzerinden geldiğini görüyoruz.

Tek bir yerden yöneterek kodun genel yapısını bozmadan değişime açık bir kod geliştirmiş olduk. Projenin son hali :

5- Dependency Injection Container

Projemizde dependency injection kullanmak için birçok 3. parti kütüphane bulunmaktadır. Bu kütüphanelerden birini yükleyerek projede kullanabiliriz. Örneğimizi .NET Core’da yaptığımız ve .NET Core içerisinde de hali hazırda bir dependency injection mekanizması bulunduğu için ekstra bir kütüphane kurmadan örneğimize devam ediyoruz.

Dependency injection uygulanan nesnelerin yaşam sürelerini(lifetime) belirlemek için 3 farklı seçenek bulunuyor.

Bölüm 4'e kadar henüz bir container kullanmıyorduk. Şimdi default gelen container ile nasıl bir yol izleriz ona bakalım. Startup sınıfında bulunan ConfigureServices metodunun içerisinde 3 farklı yöntemle nesne örneği oluşturmasını sağlayabiliriz. Startup sınıfı .NET Core projelerinin başlangıç noktasıdır, farklı platformda kod yazıyosanız bu yapılandırmayı benzeri bir sınıf veya metotta yapabilirsiniz.

Görüldüğü gibi artık bağımlılığı tek bir noktaya indirdik. Az sonra Controller tarafında doğrudan IConnection ile çalışacak şekilde yapımızı kuracağız. Dolayısıyla business vb. katmanlarda artık OracleConnection gibi bir sınıfa bağımlı kalmayacağız. Sonraki aşamalarda MsSQLConnection gibi farklı bir bağlantı sınıfı kullanmamız gerekirse yapmamız gereken tek değişiklik yukarıdaki kod parçasındaki ifadeyi services.AddSingleton<IConnection, MsSQLConnection> ile güncellemek olacaktır.

Controller tarafında tek yapmamız gereken bu bağımlılığı constructor içerisine inject etmek. Görüldüğü üzere projemizde bağımlılık yönetimini, nesne yaşam döngüsünü bizim yerimize container üstlenmiş oldu. IoC Container kullanarak yazdığım proje ise aşağıdaki gibidir.

Kodlara github hesabımdan ulaşabilirsiniz.

İyi Çalışmalar..

Originally published at http://devnot.com.

Software Engineer @hepsiburada

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store