İkisi ile neden DI konteynerinin neden bir servis belirleyiciden daha iyi olduğunu anlamanın en kolay yolunun neden bağımlılık inversiyonu yaptığımızı düşünmek olduğunu düşünüyorum.
Bağımlılık inversiyonu yapıyoruz, böylece her sınıf açıkça operasyon için neye bağlı olduğunu belirtir . Bunu yapıyoruz çünkü bu, elde edebileceğimiz en gevşek eşleşmeyi yaratıyor. Kaplin ne kadar gevşerse, test etmek ve yeniden yönlendirmek daha kolay bir şeydir (ve kodun daha temiz olması nedeniyle genellikle gelecekte en az yeniden düzenlemeyi gerektirir).
Aşağıdaki sınıfa bakalım:
public class MySpecialStringWriter
{
private readonly IOutputProvider outputProvider;
public MySpecialFormatter(IOutputProvider outputProvider)
{
this.outputProvider = outputProvider;
}
public void OutputString(string source)
{
this.outputProvider.Output("This is the string that was passed: " + source);
}
}
Bu sınıfta, açıkça bir IOutputProvider'a ve bu dersin çalışmasını sağlamak için başka hiçbir şeye ihtiyacımız olmadığını belirtiyoruz. Bu tamamen test edilebilir ve tek bir arayüze bağlı. Bu sınıfı, uygulamamın herhangi bir yerine taşıyabilirim, farklı bir proje de dahil ve tek ihtiyacı IOutputProvider arayüzüne erişim. Diğer geliştiriciler bu sınıfa ikinci bir bağımlılık gerektiren yeni bir şey eklemek isterlerse , kurucuda ihtiyaç duydukları şey hakkında net olmaları gerekir.
Servis bulucu ile aynı sınıfa bir göz atın:
public class MySpecialStringWriter
{
private readonly ServiceLocator serviceLocator;
public MySpecialFormatter(ServiceLocator serviceLocator)
{
this.serviceLocator = serviceLocator;
}
public void OutputString(string source)
{
this.serviceLocator.OutputProvider.Output("This is the string that was passed: " + source);
}
}
Şimdi hizmet bulucuyu bağımlılık olarak ekledim. İşte hemen aşikar olan problemler:
- Bununla ilgili ilk sorun , aynı sonucu elde etmek için daha fazla kod gerektirmesidir. Daha fazla kod bozuk. Daha fazla kod değil ama yine de daha fazla.
- İkinci sorun, bağımlılığımın artık açık olmamasıdır . Hala sınıfa bir şey enjekte etmem gerekiyor. Şimdi hariç, istediğim şey açık değil. İstediğim şeyin özelliğine gizlenmiş. Şimdi sınıfı farklı bir düzeneğe taşımak istersem, hem ServiceLocator hem de IOutputProvider'a erişmem gerekiyor.
- Üçüncü sorun, sınıfa kod eklerken aldıklarını bile anlamayan başka bir geliştirici tarafından ek bir bağımlılığın alınabilmesidir .
- Son olarak, bu kodu test etmek daha zordur (ServiceLocator bir arayüz olsa bile) çünkü sadece IOutputProvider yerine ServiceLocator ve IOutputProvider ile alay etmek zorundayız
Öyleyse neden servis bulucuyu statik bir sınıf yapmıyoruz? Hadi bir bakalım:
public class MySpecialStringWriter
{
public void OutputString(string source)
{
ServiceLocator.OutputProvider.Output("This is the string that was passed: " + source);
}
}
Bu çok daha basit, değil mi?
Yanlış.
Diyelim ki, IOutputProvider, diziyi dünyanın dört bir yanındaki on beş farklı veritabanında yazan ve tamamlanması çok uzun süren çok uzun süredir çalışan bir web servisi tarafından uygulanıyor.
Bu sınıfı test etmeye çalışalım. Test için farklı bir IOutputProvider uygulamasına ihtiyacımız var. Testi nasıl yazıyoruz?
Bunu yapmak için, test tarafından çağrıldığında farklı bir IOutputProvider uygulamasını kullanmak için statik ServiceLocator sınıfında bazı fantezi yapılandırmalar yapmamız gerekir. Bu cümleyi yazmak bile acı vericiydi. Uygulanması zorlaşacak ve bakım kabusu olacaktı . Özellikle sınamak için denediğimiz sınıf değilse, sınava yönelik bir sınıfı hiçbir zaman özel olarak değiştirmememiz gerekmez.
Öyleyse şimdi ikisinden birine bıraktınız: a) ilgisiz ServiceLocator sınıfında rahatsız edici kod değişikliklerine neden olan bir test; veya b) hiç test yok. Ve daha az esnek bir çözümle baş başa kaldın.
Yani hizmet bulucu sınıfı vardır yapıcı içine enjekte edilecek. Bu, daha önce bahsettiğimiz spesifik problemlerden ayrıldığımız anlamına gelir. Hizmet bulucu daha fazla kod gerektirir, diğer geliştiricilere ihtiyaç duymadığı şeylere ihtiyacı olduğunu söyler, diğer geliştiricilere daha kötü kod yazmasını teşvik eder ve bize ileriye doğru daha az esneklik sağlar.
Basitçe söylemek gerekirse servis bulucuları bir uygulamada eşleşmeyi arttırır ve diğer geliştiricilerin yüksek eşleşmiş kod yazmasını teşvik eder .