Nedir Bu Dependency Injection? Daha Bağımsız Sınıflar Nasıl Oluşturulur?

İsmail Güngör
4 min readApr 3, 2019

--

Herkese merhaba,

Daha önce hiç projenizde kullandığınız resim kütüphanesini değiştirmeniz gerektiği durumlar olmuş muydu? Peki farklı bir kütüphaneye geçerken “o kadar kodu kim değiştirecek şimdi” diye mi düşünmüştünüz?

Bu yazımda sizlere, yapılan hatalardan sonra öneminin daha çok anlaşıldığı Dependency Injection (Bağımlılık Enjeksiyonu) kavramından bahsedeceğim.

Dependency Injection (Bağımlılık Enjeksiyonu)

Bu prensip, temel olarak sınıfların birbirine mümkün olduğunca düşük derecede bağlı olmasına dayanmaktadır. Peki yüksek derecede bağımlılık nasıl olmaktadır? Aşağıdaki kod örneğini inceleyelim.

Bir Cafe sınıfımız var ve içerisinde parametre olarak ürün ismi alan bir method görülmektedir. Method içerisinde ise Cooker nesnesi üretilip prepareProduct(name) methoduyla Product nesnesi dönülmüştür.

Cafe sınıfı için şunu söyleyebiliriz: Bu sınıf Cooker nesnesi olmadan ürün sağlayamaz. Yani bu sınıf görevini yerine getirmek için Cooker nesnesine bağlıdır. Bu bağlılık ise 4. satırdaki yeni bir Cooker nesnesi üretilerek sağlanmıştır. Bu bağımlılığa yüksek derecede bağımlılık diyebiliriz.

Dependecy Injection teriminin Dependency kısmını oluşturur.

Bu tarz durumlardan mümkün olduğunca kaçınmak gerekmektedir. Çünkü, kafe sahibi bir zaman sonra “Artık benim aşçıya ihtiyacım yok, yemek değil içecek satacağım.” diyebilir. Bu durumda yeni bir Barmen sınıfı açar, prepareProduct methodu ekleriz ve Cooker sınıfına artık ihtiyacımız kalmaz.

Ama bir dakika!

Cafe sınıfının 4. satırını değiştirmemiz gerekecektir. Artık Cooker değil Barmen sınıfı üreteceğiz! Yazdığımız projede cafenin başka şubeleride olduğunu düşünelim. O zaman bütün şubelerdeki 4. satır benzeri kodları da değiştireceğiz. İşler biraz karıştı sanırım.

Bu karışıklığı engellemek için iki aşamalı düzenleme yapacağız:

  • Cooker nesnesi sınıf içerisinde oluşturulmayıp, “constructor”da parametre olarak verilecektir.

Dependency Injection teriminin Injection kısmını oluşturur.

  • İleride kafe sahibinin nasıl davranacağını tahmin edemediğimiz için bu iki sınıfı da türetebileceğimiz ortak bir yapı (interface) oluşturacağız. Bu yapıyı iki sınıfıda implement edip artık Cooker, Barmen gibi sınıf örneği değil, arayüz örneği oluşturacağız.

Hadi başlayalım!

Öncelikle Cooker sınıfını method içerisinde oluşturmayıp, constructorda parametre olarak verelim.

İlk örneğe göre bağımlılığı biraz daha azalttık. Ancak sorun hala devam ediyor. Aşçı değil de barmen çalıştırmak istersek, bu sefer constructordaki Cooker sınıfını Barmen olarak değiştiriceğiz!

Peki iki çalışan sınıfını da Personnel adlı bir interfaceden türerip, constructora türetilen bu nesneyi verirsek?

Personnel

Ortak bir yapı olan arayüzümüzdür. Bütün çalışan sınıflarına, artık bu arayüzü uygulayacağız. Yeni bir çalışan sınıfı açsak bile aynı methodlara sahip olacağı için bize ilerde sorun çıkarmayacaktır.

Cooker

Aşçı sınıfıdır. Görüldüğü gibi Personnel arayüzü uygulanmıştır.

Barmen

Barmen sınıfıdır. Görüldüğü gibi Personnel arayüzü uygulanmıştır.

Şunu da belirtmek isterim. İki personel sınıfı da sanki aynı işleri yapıyormuş gibi görülüyor. İkisi de Product nesnesi oluştururken, parametre olarak malzemeler (ingredients) nesnesi veriyor diyebilirsiniz. Ancak malzemelerin ayarlanması, hangi malzemeden ne kadar kullanacağı gibi işlemleri, her sınıf kendisi yapacaktır.

Şimdi düzenlenmiş haliyle Cafe sınıfımızı görelim.

Artık bu sınıfla oynamadan çalışan tipini değiştirebiliriz. Tek yapmamız gereken Personnel arayüzünden türetilen nesneleri (Coooker veya Barmen) parametre olarak vermektir. Nasıl yaptığımız görelim!

Yukarıda öncelikle cooker nesnesi üretip Cafe sınıfına parametre olarak verdik. Daha sonra, barmen çalıştırmak istediğimizde ise barmen nesnesi üretip Cafe sınıfına parametre olarak verdik. Her iki durum için de Cafe sınıfı içerisinde herhangi bir değişiklik yapmamıza gerek kalmadı.

Dependency Injection kavramını anlattığımıza göre artık ilk sorunumuza geri dönelim.

Uygulama içerisinde resim kütüphanemizi değiştirmenin kolay yolu nedir?

Projemize Picasso ve Glide, iki resim kütüphanesini de ekleyelim.

//Picasso
implementation 'com.squareup.picasso:picasso:2.71828'

//Glide
implementation 'com.github.bumptech.glide:glide:4.9.0'

Öncelikle resim yüklemek için kütüphaneleri aşağıdaki şekilde kullanıyorsanız, bu kullanımdan kesinlikle kaçınmanız gerekmektedir.

class MainActivity : AppCompatActivity() {

private lateinit var ivMain : ImageView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ivMain = findViewById(R.id.iv_main) Picasso.get()
.load("https://www.erasmuslife.net/img/tshirt/8.jpg")
.into(ivMain)

}
}

Bir Activity içerisinde 5 farklı ImageView olduğunu ve 5 tane Activity içerisinde de bu şekilde kullandığınızı düşünelim. Yani 25 farklı yerde bu şekilde kullandık.

Eğer Picasso’yu Glide ile değiştirmek isterseniz 25 farklı yerde değişiklik yapmanız gerekecektir. Büyük bir projede çalıştığınızı düşünürseniz bu sayı giderek artacaktır.

Peki en küçük değişiklikle geçiş yapmak için ne yapabiliriz ?

Dependency Injection kurallarına uyacağız. Yani iki farklı yardımcı sınıfımız olacak ve biri Picasso işlemlerini yapacak, diğeri ise Glide işlemlerini yapacak. Ancak bu iki yardımcı sınıfı da tek bir çatı altında (bir arayüzde) toplayacağız. Eğer geçiş yapmak istersek, sadece ürettiğimiz sınıf tipini değiştireceğiz!

IImageProcess

Arayüz sınıfımızdır. İki farklı kütüphanenin kullanacağı methodları buraya yazıyoruz.

https://gist.github.com/ismailgungor/7cf7bdcc9ee4966dae65b97306e824e6

Şimdi Picasso için yardımcı sınıfımızı görelim.

PicassoImageHelper

Picasso için yazdığımız yardımcı sınıftır. IImageProcess arayüzünü uyguladık ve methodların içlerini Picasso kütüphanesine göre doldurduk.

https://gist.github.com/ismailgungor/e712ce6d322efabf89636c8b28c49130

Şimdi Glide için yardımcı sınıfımızı görelim.

GlideImageHelper

Glide için yazdığımız yardımcı sınıftır. IImageProcess arayüzünü uyguladık ve methodların içlerini Glide kütüphanesine göre doldurduk.

https://gist.github.com/ismailgungor/59b37cf142f6b5c28b400a321f055f3d

Şimdi ise bu iki kütüphane arasında tek satır kodla, nasıl geçiş yaptığımız görelim!

https://gist.github.com/ismailgungor/73fd77af5e81fdd268cbf7dc4763fce6

Yukarıda sadece 15. satırda eşitliğin sağ tarafını değiştirerek Picasso kütüphanesinden Glide kütüphanesine geçiş yapabiliyoruz. Bunun nedeni iki yardımcı sınıfı da tek bir arayüzden oluşturmuş olmamızdır!

Sonuç

Dependency Injection, büyük projelerde kod ile çok oynamadan projenin yapısında köklü değişikler yapabilmemize imkan kılan bir yöntemdir.

Teşekkürler Dependecny Injection!

Yazımı okuduğunuz için teşekkür ederim, sevgiyle kalın!

--

--