Bağımlılık yerleştirme (DI), programlamada yaygın olarak kullanılan bir tekniktir. bir uygulamadır. DI ilkelerine uyarak iyi bir uygulama mimarisinin temellerini atabilirsiniz.
Bağımlılık yerleştirmeyi uygulamak, size aşağıdaki avantajları sağlar:
- Kodun yeniden kullanılabilirliği
- Yeniden düzenleme kolaylığı
- Test kolaylığı
Bağımlılık yerleştirmenin temelleri
Özellikle Android'de bağımlılık yerleştirmeyi ele almadan önce bu sayfanın bağımlılık yerleştirmenin işleyiş şekline dair daha genel bir bakış sunduk.
Bağımlılık yerleştirme nedir?
Sınıflar için genellikle diğer sınıflara referanslar gerekir. Örneğin, Car
sınıfı
bir Engine
sınıfına referans gerekebilir. Bu gerekli sınıflar
dependencies olarak ayarlanmıştır. Bu örnekte Car
sınıfı şuna bağımlıdır:
Engine
sınıfının bir örneğini burada görebilirsiniz.
Bir sınıf, ihtiyacı olan nesneyi üç şekilde elde edebilir:
- Sınıf, ihtiyaç duyduğu bağımlılığı oluşturur. Yukarıdaki örnekte,
Car
, kendi örneğini oluşturup başlatırEngine
. - Başka bir yerden alın. Bazı Android API'leri:
Context
alıcı vegetSystemService()
, bu işi yapın sağlar. - Parametre olarak sağlanmasını sağlayın. Uygulama bunları sağlayabilir
bağımlılıkları sınıf oluşturulduğunda veya fonksiyonlara ilettiğinde
her bir bağımlılığa ihtiyaç duyanlar için
bir fırsat bulunuyor. Yukarıdaki örnekte,
Car
kurucusu parametre olarakEngine
alır.
Üçüncü seçenek bağımlılık eklemedir. Bu yaklaşımla bir sınıfa sahip olmak yerine bağımlılıklarını örneğinin kendisinde olması gerekir.
Bir örnekle açıklayalım. Bağımlılık yerleştirme olmadan, aynı işleve sahip bir Car
kodda kendi Engine
bağımlılığını oluşturur:
Kotlin
class Car { private val engine = Engine() fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() }
Java
class Car { private Engine engine = new Engine(); public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Car car = new Car(); car.start(); } }
Bu, bir bağımlılık yerleştirme örneği değildir çünkü Car
sınıfı
kendi Engine
projesini oluşturuyor. Bu durum aşağıdaki nedenlerden dolayı sorunlara yol açabilir:
Car
veEngine
sıkı sıkıya bağlı.Car
örneği tek bir kod kullanır ve alt sınıfların veya alternatif uygulamaların kolaycaEngine
kullanılır.Car
kendiEngine
öğesini oluşturacaksa türündeki motorlar için aynıCar
öğesini yeniden kullanmak yerine iki türCar
Gas
veElectric
.Engine
ürününe ciddi düzeyde bağımlılık, testi daha da zorlaştırıyor.Car
, bir gerçek birEngine
örneği oluşturur. Bu nedenle,Engine
değerini farklı test durumlarında değiştirmek için iki kez test edin.
Bağımlılık yerleştirmede kod nasıl görünür? Her bir örnek yerine
başlatma sırasında kendi Engine
nesnesini oluşturan Car
API'si,
Oluşturucuda parametre olarak Engine
nesnesi:
Kotlin
class Car(private val engine: Engine) { fun start() { engine.start() } } fun main(args: Array) { val engine = Engine() val car = Car(engine) car.start() }
Java
class Car { private final Engine engine; public Car(Engine engine) { this.engine = engine; } public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Engine engine = new Engine(); Car car = new Car(engine); car.start(); } }
main
işlevi, Car
değerini kullanır. Car
, Engine
uygulamasına bağlı olduğundan uygulama
Engine
örneğini oluşturur ve daha sonra, bunu Car
öğesinin bir örneğini oluşturmak için kullanır. İlgili içeriği oluşturmak için kullanılan
bu DI tabanlı yaklaşımın avantajları şunlardır:
Car
ürününün yeniden kullanılabilirliği.Engine
öğesinin farklı uygulamalarınıCar
. Örneğin,Engine
adında yeni bir alt sınıf tanımlayabilirsiniz.Car
tarafından kullanılmasını istediğinizElectricEngine
. DI kullanıyorsanız tek yapmanız gereken güncellenenElectricEngine
alt sınıfının bir örneğini iletir,Car
hâlâ çalışır başka hiçbir değişiklik yapmadan kullanabilirsiniz.Car
için kolay test yapın. Farklı testlerinizi test etmek için testlerinizi senaryoları ele alacağız. Örneğin,Engine
değeri için şu adla bir test ikilisi oluşturabilirsiniz:FakeEngine
ve farklı testler için yapılandırın.
Android'de bağımlılık yerleştirmenin iki temel yolu vardır:
Oluşturucu Yerleştirme. Bu, yukarıda açıklanan şekildedir. Geçerseniz bağımlılıklarını ifade eder.
Alan Yerleştirme (veya Setter Yerleştirme). Belirli Android çerçevesi sınıfları öğeler ve parçalar sistem tarafından örneklendirildiğinden, eklemesi mümkün değildir. Alan yerleştirme ile bağımlılıklar örneklendirilir sınıf oluşturulduktan sonra. Kod şöyle görünür:
Kotlin
class Car { lateinit var engine: Engine fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.engine = Engine() car.start() }
Java
class Car { private Engine engine; public void setEngine(Engine engine) { this.engine = engine; } public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Car car = new Car(); car.setEngine(new Engine()); car.start(); } }
Otomatik bağımlılık ekleme
Önceki örnekte bağımlılıkları oluşturdunuz, sağladınız ve yönettiniz
farklı sınıfları kolayca görebilirsiniz. Buna
el ile bağımlılık ekleme veya manuel bağımlılık ekleme. Car
içinde
Mesela sadece tek bir bağımlılık vardı, ama daha fazla bağımlılık ve sınıf
bağımlılıkları manuel olarak eklemeyi daha yorucu hale getirebilir. Manuel bağımlılık ekleme
birtakım sorunlar da beraberinde getirir:
Büyük uygulamalar için, tüm bağımlılıkları alıp bunları bağlamak büyük miktarda ortak metin kodu gerektirebilir. Çok katmanlı bir üst katman için nesne oluşturmak istiyorsanız öncelikle altındaki katmanların tüm bağımlılıklarını göreceksiniz. Somut bir örnek vermek gerekirse, motor, şanzıman, şasi ve diğer parçalara ihtiyacınız olabilir. Motorda ise silindir ve buji gerekir.
Bağımlılıkları aktarmadan önce oluşturamadığınızda gecikmeli başlatmaların veya nesnelerin akışlarının kapsamını belirlemenin, özel bir kapsayıcı (ya da her bir (bağımlılıkların) bellekteki yaşamını yöneten bir kaynaktır.
Süreçleri otomatikleştirerek bu sorunu çözen kütüphaneler var ve bağımlılık sağlamaktan bahsedeceğiz. Bunlar iki kategoriye ayrılır:
Çalışma zamanında bağımlılıkları birbirine bağlayan yansıtma tabanlı çözümler.
Bağımlılıkları bağlamak için kod oluşturan statik çözümler sırasında görünür.
Dagger, Java için popüler bir bağımlılık ekleme kitaplığıdır. Kotlin ve Google tarafından sağlanan Android. Dagger, DI kullanımını kolaylaştırır bağımlılık grafiğini sizin için oluşturup yöneterek uygulamanızda kullanabilirsiniz. Google birçok bileşeni ele alan tamamen statik ve derleme zamanı bağımlılıkları düşünmeye dayalı çözümlerin geliştirilmesini ve performans Guice.
Bağımlılık yerleştirmenin alternatifleri
Bağımlılık yerleştirmeye alternatif olarak, hizmet bulma aracı ile uyumludur. Hizmet bulma aracı tasarım kalıbı da sınıfların somut bağımlılıklardan ayrıştırılmasını kolaylaştırır. Bir sınıf oluşturursunuz Bağımlılıkları oluşturan ve depolayan hizmet bulucu olarak bilinir, ardından isteğe bağlı olarak bulunduğunu öğrendik.
Kotlin
object ServiceLocator { fun getEngine(): Engine = Engine() } class Car { private val engine = ServiceLocator.getEngine() fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() }
Java
class ServiceLocator { private static ServiceLocator instance = null; private ServiceLocator() {} public static ServiceLocator getInstance() { if (instance == null) { synchronized(ServiceLocator.class) { instance = new ServiceLocator(); } } return instance; } public Engine getEngine() { return new Engine(); } } class Car { private Engine engine = ServiceLocator.getInstance().getEngine(); public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Car car = new Car(); car.start(); } }
Hizmet bulucu kalıbı, özellik açısından bağımlılık eklemesinden farklıdır. emin olun. Hizmet bulucu kalıbında, sınıflar nesnelerin yerleştirilmesini kontrol etme ve isteme; bağımlılık enjeksiyonu ile Uygulama, kontrol özelliğine sahiptir ve gerekli nesneleri proaktif olarak ekler.
Bağımlılık yerleştirme ile karşılaştırıldığında:
Bir hizmet bulucunun gerektirdiği bağımlılıkların koleksiyonu, kodu oluşturur tüm testler, aynı global kullanıcı arayüzüyle etkileşim kurması gerektiğinden, test edilmesi daha zordur. hizmet bulma aracı.
Bağımlılıklar API yüzeyinde değil, sınıf uygulamasında kodlanır. Sonuç olarak, sınıfın dışarıdan neye ihtiyacı olduğunu bilmek daha zordur. Bunun sonucunda
Car
veya hizmet bulucuda bulunan bağımlılıklar, çalışma zamanı veya test ile sonuçlanabilir hata mesajları ve referansların başarısız olmasına neden olabilir.Nesnelerin ömürlerini yönetmek, yalnızca nesnel uygulamanın ömründen başka herhangi bir şeye dayanıyor olabilir.
Android uygulamanızda Hilt'i kullanma
Hilt, Jetpack'te öneriliyor uygulama kitaplığını kullanıma sunduk. Hilt, standart bir proje yönetimi yöntemi Uygulamanızdaki her Android sınıfı için kapsayıcılar sağlayarak ve yaşam döngülerini sizin için otomatik olarak yönetmelerine yardımcı olur.
Hilt, popüler DI kitaplığının üzerine inşa edilmiştir Dagger derleme zamanı doğruluğu, çalışma zamanı performansı, ölçeklenebilirlik ve Android Studio desteği sağlamak için tasarlandı.
Hilt hakkında daha fazla bilgi edinmek için Hilt ile Bağımlılık Enjeksiyonu.
Sonuç
Bağımlılık yerleştirme, uygulamanıza aşağıdaki avantajları sağlar:
Sınıfların yeniden kullanılabilirliği ve bağımlılıkların ayrıştırılması: Değiştirmek daha kolaydır bağımlılığın uygulamaları. Ters çevirme sayesinde kodun yeniden kullanımı iyileştirildi Sınıflar artık bağımlılıklarının nasıl oluşturulduğunu kontrol edemiyor. herhangi bir yapılandırmayla çalışır.
Yeniden düzenleme kolaylığı: Bağımlılıklar, API'nin doğrulanabilir bir parçası haline gelir yüzey, böylece nesne oluşturulma zamanında veya derleme sırasında kontrol edilebilir yerine bu verileri kullanabilirsiniz.
Test kolaylığı: Sınıf, bağımlılıklarını yönetmez. Dolayısıyla, test etmek tüm araçları test etmek için farklı uygulamalardan isteyebilirsiniz.
Bağımlılık yerleştirmenin avantajlarını tam olarak anlamak için bu özelliği denemeniz gerekir Manuel bağımlılık ekleme bölümünde gösterildiği gibi uygulamanıza manuel olarak ekleyin.
Ek kaynaklar
Bağımlılık yerleştirme hakkında daha fazla bilgi için aşağıdaki ek kaynakları inceleyin.