Bağımlılık enjeksiyonu]1 hakkında, ne zaman kullanılacağı ve bunun için hangi çerçevelerin bulunduğu gibi özel sorular içeren birkaç soru zaten gönderildi. Ancak,
**Bağımlılık enjeksiyonu nedir ve ne zaman/neden kullanılmalıdır ya da kullanılmamalıdır?
Şu ana kadar bulduğum en iyi tanım James Shore tarafından yapılmış:
"Dependency Injection" 25 dolarlık bir 5 sentlik bir kavram için kullanılan terim. [...] Bağımlılık enjeksiyonu, bir örnek değişkenlerini nesneler. [...].
Martin Fowler tarafından kaleme alınan ve faydalı olabilecek bir makalesi de bulunmaktadır.
Bağımlılık enjeksiyonu, temel olarak bir nesnenin ihtiyaç duyduğu nesneleri (bağımlılıklarını) kendisinin oluşturması yerine sağlamaktır. Test için çok kullanışlı bir tekniktir, çünkü bağımlılıkların taklit edilmesine veya saplanmasına izin verir.
Bağımlılıklar nesnelere birçok yolla enjekte edilebilir (yapıcı enjeksiyonu veya setter enjeksiyonu gibi). Bunu yapmak için özel bağımlılık enjeksiyon çerçeveleri (örneğin Spring) bile kullanılabilir, ancak bunlar kesinlikle gerekli değildir. Bağımlılık enjeksiyonuna sahip olmak için bu çerçevelere ihtiyacınız yoktur. Nesneleri (bağımlılıkları) açık bir şekilde Instantiate etmek ve aktarmak, framework ile enjeksiyon kadar iyi bir enjeksiyondur.
Bağımlılık Enjeksiyonu, bağımlılığı diğer nesnelere veya framework'e (bağımlılık enjektörü) aktarır.
Bağımlılık enjeksiyonu test yapmayı kolaylaştırır. Enjeksiyon constructor aracılığıyla yapılabilir.
SomeClass()
yapıcısı aşağıdaki gibidir:
public SomeClass() {
myObject = Factory.getObject();
}
Problem:
Eğer myObject
disk erişimi veya ağ erişimi gibi karmaşık görevler içeriyorsa, SomeClass()
üzerinde birim testi yapmak zordur. Programcılar myObject
ile alay etmek zorundadır ve fabrika çağrısını kesebilir.
Alternatif çözüm:
public SomeClass (MyClass myObject) {
this.myObject = myObject;
}
myObject` doğrudan geçirilebilir, bu da test yapmayı kolaylaştırır.
Bağımlılık enjeksiyonu olmadan birim testinde bileşenleri izole etmek daha zordur.
Bu yanıtı yazdığım 2013 yılında, bu Google Testing Blog'da ana temalardan biriydi. Programcılar çalışma zamanı tasarımlarında her zaman ekstra esnekliğe ihtiyaç duymadıkları için (örneğin, hizmet bulucu veya benzer modeller için) bu benim için en büyük avantaj olmaya devam ediyor. Programcıların genellikle test sırasında sınıfları izole etmeleri gerekir.
Bağımlılık Enjeksiyonu, nesnelerin dahili olarak inşa edilmek yerine diğer kod parçalarından nesne örneklerini alacak şekilde tasarlandığı bir uygulamadır. Bu, nesnenin ihtiyaç duyduğu arayüzü uygulayan herhangi bir nesnenin kodu değiştirmeden ikame edilebileceği anlamına gelir, bu da testleri basitleştirir ve ayrışmayı geliştirir.
Örneğin, bu sınıfları göz önünde bulundurun:
public class PersonService {
public void addManager( Person employee, Person newManager ) { ... }
public void removeManager( Person employee, Person oldManager ) { ... }
public Group getGroupByManager( Person manager ) { ... }
}
public class GroupMembershipService() {
public void addPersonToGroup( Person person, Group group ) { ... }
public void removePersonFromGroup( Person person, Group group ) { ... }
}
Bu örnekte, PersonService::addManager
ve PersonService::removeManager
uygulamaları işlerini yapabilmek için GroupMembershipService
örneğine ihtiyaç duyacaktır. Dependency Injection olmadan bunu yapmanın geleneksel yolu, PersonService
yapıcısında yeni bir GroupMembershipService
örneği oluşturmak ve her iki işlevde de bu örnek niteliğini kullanmaktır. Ancak, GroupMembershipService
kurucusunun gerektirdiği birden fazla şey varsa veya daha da kötüsü, GroupMembershipService
üzerinde çağrılması gereken bazı başlatma "setters" varsa, kod oldukça hızlı bir şekilde büyür ve PersonService
artık yalnızca GroupMembershipService
e değil, aynı zamanda GroupMembershipService
in bağlı olduğu diğer her şeye de bağlıdır. Ayrıca, GroupMembershipService
bağlantısı PersonService
içine kodlanmıştır, bu da test amacıyla ya da uygulamanızın farklı bölümlerinde bir strateji kalıbı kullanmak için bir GroupMembershipService
kuramayacağınız anlamına gelir.
Dependency Injection ile, GroupMembershipService
i PersonService
içinde örneklemek yerine, ya PersonService
kurucusuna aktarırsınız ya da yerel bir örneğini ayarlamak için bir Özellik (getter ve setter) eklersiniz. Bu, PersonService
inizin artık bir GroupMembershipService
in nasıl oluşturulacağı konusunda endişelenmesine gerek olmadığı, sadece kendisine verilenleri kabul ettiği ve onlarla çalıştığı anlamına gelir. Bu aynı zamanda GroupMembershipService
in bir alt sınıfı olan ya da GroupMembershipService
arayüzünü uygulayan herhangi bir şeyin PersonService
e "inject" edilebileceği ve PersonService
in bu değişiklikten haberdar olması gerekmediği anlamına gelir.