Bu yazımda Dependency Injection- Bağımlılık Enjeksiyonu kavramını incelyecek ve basit bir örnek üzerinde nasıl uygulandığını açıklayacağım.
Dependency Injection Nedir?
Bağımlılık oluşturan parçaların ayrılıp bunların dışarıdan verilmesiyle sistem içerisindeki birbirine bağımlılığı en aza indirgemektir.
Yani örnek verecek olursak, bir class içerisinde başka bir class nesnesini kullanacaksanız new anahtar kelimesiyle bu nesneyi oluşturmamanızı söyleyen yaklaşımdır. Gereken nesneyi ya Constructor'dan ya da Setter metoduyla parametre olarak alınması gerektiğini söyler. Bu şekilde bir class içerisinde başka bir class'a ait nesneyi new anahtar kelimesiyle yaratmayız ve dışarıdan alırız. Bu bize class'ları birbirinden izole etmemizi sağlar.
Yazılımı oluşturan yapılar ( class'lar vs.) birbirleriyle kaçınılmaz olarak ilişki içerisindedir. Amaç bu ilişkiyi mümkün mertebede gevşek tutmaktır. Buna Loosely Coupled yani Gevşek Bağlılık diyoruz.
Bundan dolayı yapıların birbiriyle olan sıkı bağlarının azalacağı için uygulamaya yeni özellikler ekleyip çıkarmak kolaylaşmaktadır.
Örnek verecek olursak;
Elimizde "A" ve "B" class'ları olsun. "A" class'ında "B" nesnesi üretildiğini düşünelim. Şuan "A" class'ı "B" class'ına bağlı hale geldi.
Daha sonra günün birinde "B" class'ında bir değişiklik yapma mecburiyeti olduğunda aynı zamanda gidip aynı değişikliği "A" classında da yapmak zorundayız. 1000 tane class "B" classına bağlı ise 1000 classta da gidip değişiklik yapmak zorundayız. Bu büyük projeler için büyük bir iş demektir. Peki bundan kurtulmak için ne yapmalıyız ? Tabikide bağımlılıkları azaltmalıyız ki böyle durumlarla karşılaşmayalım. İşte böyle durumlarda eğer Dependency İnjection tekniği uygularsak minumum değişiklik ile bu işlerden kurtulabiliriz.
Dependency Injection bir Design Pattern'dir.
Dependency Injection Örnek
Dependency Injection iki şekilde uygulanabilir. Yazımızın başlarında bahsettiğmiz gibi bu teknikler;
- Constructor ile ( Constructor Injection- Constructor Based Dependency Injection )
- Setter ile ( Setter Injection- Setter Based Dependency Injection )
Javayı az çok bilenlerin aklında şuan nasıl yapılcağı konusu biraz belirmiştir. Yazımızın başında belirttiğimiz gibi bağımlı olunan nesneyi dışarıdan vereceğiz. Bunuda Setter veya Constructor kullanarak yapacağız.
Tabi bunları injecte ederken yani dışarıdan verirken ileride yeni eklenecek durumlarıda göz önünde bulundururak yapacağız. Yani interface'ler üzerinden bu işi yürütürsek ileride eklenen yeni class'ları injecte ederken herhangi bir zorluk yaşamayız.
Peki nasıl? Örneklerle inceleyelim.
İlk olarak örneğimizde DI uygulamadan yapılmış olanı inceleyelim.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| public class Araba { public void GazVer() { //... } public void FrenYap() { //... } public void SagaSinyal() { //... } public void SolaSinyal() { //.. } } public class Vasita { Araba araba; public Vasita() { araba = new Araba(); } public void Kullan() { araba.GazVer(); araba.SagaSinyal(); araba.FrenYap(); araba.SolaSinyal(); } } |
Yukarıdaki örnekte Vasita class'ı Araba nesnesine bağlı bir vaziyettedir. Bu durumda Vasita nesnesi üretilirken "Araba" nesneside üretilmelidirki bu nesneye ait özellikler "Kullan" metodunda kullanılabilinsin. İleride bir gün "Araba" class'ı içerisnde bir değişiklik yaptığımızda gelip "Vaista" class'ında da değişiklik yapmamız gerekebilir. Bu gibi 100 tane class düşünürsek işimiz hayli uzun oluyor.
"Vasita" class'ına bir gün "Araba" değilde "Otobüs" nesnesi geçmek istersek, "Vasita" class'ı içine gelip "Kullan" metodunun içerisindeki komutları güncellemem gerekebilir.
Şimdi öyle bişey yapalım ki "Vasita" nesnesi hem "Araba" hemde "Otobüs" nesenesini kullanabilsin ve bundan haberi olmasın. Hatta ileride "Motor" nesnesi diye bir ihtiyaç doğarsa bunuda karşılayabilsin.
Peki nasıl olacak?
Dependency Injection design patternini uygulamak için öncelikler bir interface tanımlamamız gerekmektedir. Tanımlayacağımız bu interfaceyi tüm class'lar implement edecek ve parametre olarak bu interface kalıbını kabul eden constructor ve setter metoduna class'ı gönderebileceğiz.
1
2
3
4
5
6
7
| public interface ITasit { void GazVer(); void FrenYap(); void SagaSinyal(); void SolaSinyal(); } |
Oluşturduğumuz ITasit interfacesinden "Araba", "Otobüs", "Motor" vs. taşıtları bu interfaceten türeteceğiz.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| public class Araba implements ITasit { public void GazVer() { //... } public void FrenYap() { //... } public void SagaSinyal() { //... } public void SolaSinyal() { //.. } } public class Otobus implements ITasit { public void GazVer() { //... } public void FrenYap() { //... } public void SagaSinyal() { //... } public void SolaSinyal() { //.. } } public class Motor implements ITasit { public void GazVer() { //... } public void FrenYap() { //... } public void SagaSinyal() { //... } public void SolaSinyal() { //.. } } |
Bu şekilde ilgili class'ları ITasit interfacesiyle türettik.
Şimdi Dependency Injection uygulamaya sıra geldi.
Yazımızın başında 2 şekilde uygulayabileceğimizden bahsetmiştim. Bunları teker teker inceleyeceğiz.
Constructor Injection
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
| class public Vasita { ITasit _tasit; public Vasita(ITasit tasit) { _tasit = tasit; } public void Kullan() { _tasit.GazVer(); _tasit.SagaSinyal(); _tasit.FrenYap(); _tasit.SolaSinyal(); } } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
| class public Program { public static void main(string[] args) { ITasit araba = new Araba(); Vasita vasitaAraba = new Vasita( araba); vasitaAraba.Kullan();
ITasit otobus= new Otobus(); Vasita vasitaOtobus = new Vasita( otobus); vasitaOtobus.Kullan();
ITasit motor= new Motor(); Vasita vasitaMotor = new Vasita( motor); vasitaMotor.Kullan(); } } |
Yukarıdaki kodu incelersek, "Vasita" class'ı içerinde ITasit interface'si tipinde bir nesne declare ediliyor. Ardından constructor içerisinde ITasit interfacesi tipinde bir nesneye eşitleniyor. Yani "Vasita" sınıfına ITasit interface tipinde bir nesne gerekiyor. Yukarıda bakıldığında "Araba", "Otobüs", "Motor" classları "ITasit" interfacesini implement ettiği için eğer bu class'lardan bir nesne üretilirse "Vasita" sınıfına bu nesneler gönderilebilir. Yani bu haliyle "Vasita" sınıfına isterseniz "Araba", isterseniz "Otobüs" isterseniz de "Motor" nesnesi üretip verebilirsiniz. ( Bu nesneler "ITasit" interfacesini implement etmek zorunda ( Polimorfizm kuralı gereği))
Olaya "Vasita" sınıfı tarafından bakarsak, "Vasita" sınıfı kendine verilen nesnenin ne olduğu ile ilgilenmiyor. Sadece "ITasit" interfacesine cast yapabilir mi diye bakıyor. Yani gelen nesenenin interface de tanımlı metodları "Vasita" sınıfını ilgilendiriyor. İçeriğinin ne olduğuyla ilglenmiyor. Mesela GazVer() metodu "Motor" nesnesi için kolu çevirmek iken, "Otobus" nesnesi için pedala basmak ama "Vasita" sınıfı sadece GazVer() metoduyla ilgileniyor içeriğiyle değil.
Bu sayede "Vasita" sınıfının farklı sınıflara bağımlılığı azalıyor.
Setter Injection
Detaylar yukarıda bahsettiğimin aynısı. Sadece uygulanış biçimi set fonksiyonu üzerinden olacak.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
| public class Vasita { public ITasit tasit;
public void setTasit(ITasit tasit)
{
this.tasit = tasit;
}
public void Kullan() { tasit.GazVer(); tasit.SagaSinyal(); tasit.FrenYap(); tasit.SolaSinyal(); } } |
Setter Injection yöntemi için kullanımı aşağıdaki gibi yapmalısınız.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
| public class Program { public static void main(string[] args) {
ITasit araba = new Araba();
Vasita vasitaAraba = new Vasita();
vasitaAraba.setTasit(araba );
vasitaAraba.Kullan();
ITasit otobus= new Otobus();
Vasita vasitaOtobus = new Vasita();
vasitaOtobus.setTasit(otobus);
vasitaOtobus.Kullan();
ITasit motor= new Motor();
Vasita vasitaMotor = new Vasita();
vasitaMotor.setTasit(motor);
vasitaMotor.Kullan();
} } |
Görüldüğü üzere Dependency Injection kodda bağımlılığı azaltıp, ileride eklenecek özellikler için rahatlık sağlamaktadır.
Detay:
Bu özellik aslında Polimorfizm ile sağlanır. Yani bir class bir interfaceyi implement eder. Bu class'ı implemet ettiği interface tipinde casting yapabiliriz. Bu sayede ilgili constructor veya setter metoduna interface yerine bu class'ı gönderebiliriz.
Kaynakar:
http://www.gencayyildiz.com/blog/dependency-injection-nedir-nasil-uygulanir/
http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/
Hiç yorum yok:
Yorum Gönder