JavaScript Bağımlılık Enjeksiyonu | sıcak çevrimiçi



  1. JavaScript’te Bağımlılık Enjeksiyonu

Kitaplıklar ve çerçeveler, bir uygulama içindeki bağımlılıkları yönetmede daha fazla esneklik kazanmak için bağımlılık eklemeye güvenir.


Java ve PHP gibi programlama dillerinde, bağımlılık enjeksiyonu yıllardır yerleşik bir tasarım modeli olmuştur. Ve son yıllarda, JavaScript dünyasına da girdi. Muhtemelen bu tasarım modelini neredeyse evrensel olarak kullanan çerçevelerin en iyi bilinen temsilcisi Angular’dır. Ancak Dependency Injection (DI), örneğin Nest tarafından sunucu tarafında da kullanılır. Tek soru, React gibi diğer yerleşik kitaplıkların neden bu tasarım modelini tamamen görmezden geldiğidir.

Bir sonraki adımda JavaScript’te DI’nin somut uygulamasına geçmeden önce, tasarım modelinin arkasındaki teoriye bakalım. DI, çalışma zamanında bağımlılıkların kullanılabilirliği ile ilgilidir. Derleme veya başlatma zamanında bireysel öğelerin zaten tanımlandığı modüler sistemin aksine DI, uygulama üzerinde çok daha hassas kontrol sağlar. Ek olarak DI, test ortamı için bağımlılıkları değiştirerek nesne testini kolaylaştırır. DI’nin çalışması için DI uygulayan kitaplıklar, enjekte edilebilir sınıfların kaydedileceği bir mekanizma sağlar. Uygulamadaki bir sınıf daha sonra hangi bağımlılıklara ihtiyaç duyduğunu belirtir ve kitaplık, sınıfın bağımlılığın bir örneğini almasıyla ilgilenir. Oldukça soyut görünüyor, bu yüzden Nest’teki somut bir örneğe bakalım.

HAKKINDA yuvada


Nest, geliştiricilerin web arayüzleri oluşturmasına yardımcı olan, sunucu tarafı bir JavaScript çerçevesidir. İşlevsellik genellikle bir veya daha fazla modüle bölünür. Her modül, arabirim uç noktalarını içeren denetleyicilere sahiptir. Gerçek iş mantığı, DI aracılığıyla yüklenen sağlayıcılarda yatmaktadır. DI örneğimiz için, iki GPS koordinatı arasındaki mesafeyi hesaplayan bir arayüz uyguluyoruz. Temel, GPS ile ilgili tüm sorunları içeren teknik bir modüldür, bizim durumumuzda mesafenin hesaplanmasıdır. Modül, geniş anlamda DI için bir kaptır, ancak aynı zamanda modüle giriş noktalarını da içerir. Ön uçtaki Angular gibi Nest de TypeScript ve Decorator ile çalışır. Bu dekoratör, bir sınıf veya işlev hakkında meta bilgi ekler. Aşağıdaki kod, denetleyicinin ve hizmetin zaten kayıtlı olduğu modülü gösterir:

import { Module } from '@nestjs/common';
import { DistanceController } from './distance/distance.controller';
import { DistanceService } from './distance/distance.service';

@Formlar({
denetleyiciler: [DistanceController],
sağlayıcılar: [DistanceService]
})
GpsModule sınıfını dışa aktar {}

Denetleyiciler başlangıç noktasıdır: modüller gibi dekoratörlerle genişletilmiş basit TypeScript sınıflarıdır. Aşağıdaki liste, denetleyici kodunu içerir:

import { Body, Controller, Get } from '@nestjs/common';
import { Point } from 'src/point.interface';
import { DistanceService } from './distance.service';

@Kontrolör(‘gps/mesafe’)
DistanceController dışa aktarma sınıfı {
yapıcı (özel salt okunur mesafe Hizmeti: Distance Hizmeti) {}

@Get() mesafe(@Body() koordinatları: Nokta[]): sayı {
sabit a = koordinatlar[0];
sabit b = koordinatlar[1];

return this.distanceService.calculate(a, b);
}
}


Denetleyici dekoratörleri, arayüzün davranışını belirler. Sınıf dekoratörü, URL yolunu ve dosya dekoratörünü ayarlar. distancemethod, kullanıcı yola girdiğinde bu yöntemin yürütüleceğini tanımlar. GPS/mesafe HTTP GET isteği ile. Yöntem, istek gövdesine doğrudan gövde dekoratörü aracılığıyla erişebilir. Denetleyici yalnızca arabirimle ilgilenir, istekten veri çıkarır ve gelen verileri doğrular. Bu nedenle asıl iş mantığı artık denetleyicide değil, bir hizmettedir. Bu ayırmanın avantajı, mantığın istek ve yanıt işlemeden ayrı olarak test edilebilmesidir.

Algoritmayı değiştirmek nispeten basittir, çünkü denetleyicinin kendisinin değiştirilmesi gerekmez, yalnızca enjekte edilen bağımlılık ayarlanır. Anahtar, sözde yapıcı enjeksiyonudur. Yapıcı, Nest enjektörü tarafından değerlendirilen bir parametre içerir. Uygulama başladığında Nest denetleyiciyi başlatırsa, enjektör etkinleşir ve modül yapılandırmasına göre belirtilen hizmeti başlatır. Bu daha sonra yukarıdaki denetleyici sınıfının içindedir. distanceService– Mülk mevcut. Servis kodunun kendisi nispeten belirsizdir. Geçmiş iki GPS koordinatına göre mesafeyi metre cinsinden hesaplar ve döndürür:

import { Injectable } from '@nestjs/common';
import { Point } from 'src/point.interface';

@Enjektabl()
dışa aktarma sınıfı DistanceService {
hesapla(a: Nokta, b: Nokta): sayı {
sabit yarıçap zemin = 6371e3;
const latARad = a.lat * Math.PI/180;
const latBRad = b.lat * Math.PI/180;
const deltaLatRad = (b.lat – a.lat) * Math.PI/180;
const deltaLonRad = (b.lon – a.lon) * Math.PI/180;

const x = Math.sin(deltaLatRad/2) * Math.sin(deltaLatRad/2) + Math.cos(latARad) * Math.cos(latBRad) * Math.sin(deltaLonRad/2) * Math.sin(deltaLonRad/ 2);
const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1-x));

dönüş alanıYarıçap * c;
}
}

En basit durumda, enjektör tarafından kullanılan hizmet adı ve sınıf adı aynıdır. Mesafe algoritmasının artık optimize edilmiş bir sürümle değiştirilmesi gerektiğini varsayarsak, bu, sınıfı değiştirerek veya modül yapılandırmasını değiştirerek yapılabilir. Bu durumda, hizmet artık doğrudan değil, aşağıdaki kodda da görülebileceği gibi bir nesne biçiminde başvurulur. bu durumda, OptimizedDistanceService-sınıf kullanıldı:

@Module({
controllers: [DistanceController],
providers: [{
provide: DistanceService,
useClass: OptimizedDistanceService,
}]
})
export class GpsModule {}

Algoritma alışverişi esnekliğine ek olarak DI, özellikle test söz konusu olduğunda net avantajlara sahiptir. Yine Nest’teki somut uygulamaya bakalım:

import { Test, TestingModule } from '@nestjs/testing';
import { DistanceController } from './distance.controller';
import { DistanceService } from './distance.service';

const newYork = { enlem: 40.6943, boylam: -73.9249 };
sabit tokyo = { enlem: 35.6897, boylam: 139.6922 };
sabit mesafe = 10853705.986613212;

tarif(‘DistanceController’, () => {
denetleyiciye izin ver: DistanceController;

BeforeEach(zaman uyumsuz () => {
const modülü: TestingModule = bekleyin Test.createTestingModule({
denetleyiciler: [DistanceController],
sağlayıcılar: [DistanceService]
}).overrideProvider(DistanceService).useValue({
hesapla() { dönüş mesafesi; }
}).doldurun();

denetleyici = modül.get(Mesafe Denetleyici);
});

it(‘New York ile Tokyo arasındaki mesafeyi hesaplamalı’, () => {
const sonucu = controller.distance([newYork, tokyo]);
wait(sonuç).toBe(mesafe);
});
});

Varsayılan olarak Nest CLI, kendisiyle oluşturulan tüm yapılar için bir test oluşturur. onun için de öyle DistanceController. Dosyayla birlikte gelen yükleme yordamı beforeEachfonksiyon tanımlanır, her testten önce yeni bir test modülünün oluşturulmasını sağlar. Burada geliştiriciler, bir test çalıştırması için gereken tüm yapıları kaydedebilir. Bizim durumumuzda, bunlar DistanceController ve DistanceService. Testler, orijinal hizmeti değil, test için özel olarak tanımlanmış bir sahte hizmeti kullanır.

Bu kurulum nedeniyle Nest’in enjektör bileşeni, DistanceService-Aşağıdakilerin bağımlılığı useValue belirtilen değer kullanılmalıdır. Bu sahte hizmet, calculateYöntem, nasıl çağrıldığına bakılmaksızın her zaman mesafe için sabit bir değer döndürür. Bunun avantajı, denetleyici testinin hizmeti değil, yalnızca denetleyicinin kendisini test etmesidir. Bunun sonucu, testin basit bir şekilde denetleyicideki hatalar nedeniyle de başarısız olabilmesidir. Testin kendisi dosyayı çağırır distanceistek gövdesinin yerini alan bir dizi koordinat noktası ile denetleyici yöntemi. Denetleyiciden gelen geri bildirim senkronize olduğundan, async/await girmek gibi ek önlemlere gerek yoktur. Geriye kalan tek şey, çağrı yaparak sonucu kontrol etmektir. expect-İşlev.

Yerleşik DI’ye alternatifler


Şimdiye kadar yalnızca bir entegre çözümü inceledik, DI by Nest. Ancak, kullanılan çerçeveden bağımsız olarak DI sunan kitaplıklar da vardır. Bunlar özellikle bireysel çözümler ve kendi çerçeve yaklaşımları için uygundur. Bu tür kitaplığın oldukça popüler bir örneği Inversify’dır. Uygulama, Nest veya Angular gibi entegre bir çözümden biraz daha karmaşıktır:

  1. Arayüz ve Tür Bildirimi: Tersine Çevirme, bağımlılık referanslarının somut sınıflara değil, soyutlamalara yapılması gerektiği önerisini izler.
  2. Bağımlılıkları belirtin: Nest gibi Inversify da dekoratörlerle çalışır. the @injectable-Dekoratör, DI ile çalışan sınıfları işaretler. the @inject-Dekoratör, kodda bağımlılıkların gerçekten ayarlandığı yerleri işaretler.
  3. DI Konteyneri Oluşturun: Konteyner örneği, soyut bağımlılıkları somut sınıflarla birlikte paketler.
  4. Bağımlılıkları çözme: get-Konteyner örneği yöntemi, bağımlılıkları çözmenize ve ardından somut nesnelerle çalışmanıza olanak tanır.
Neden bazı kitaplıklarda ve çerçevelerde bir DI yok?


React, hiç DI kullanmayan popüler bir kitaplığın önemli bir temsilcisidir. Nest gibi çerçevelerin aksine React, sınıflarla çok daha az çalışır. Modern React uygulamalarındaki çoğu bileşen, işlevler olarak uygulanır. Bu işlevler, sözde donanımlar hakkında argümanlar biçiminde bilgi alır. Bileşen entegrasyonu sırasında aksesuarlar etkilenebilir, bu da bileşen testini kolaylaştırır. Nest veya Angular’da bulunan formdaki hizmetler React’te mevcut değildir. Çoğu durumda, geliştiriciler bu amaç için saf işlevleri kullanırlar ve bu işlevler de iletilen bağımsız değişkenlerle denetlenir.

Test söz konusu olduğunda, React ayrıca farklı bir yaklaşım benimsiyor ve bileşenlerin bir kara kutu testi şeklinde daha çok kullanıcı bakış açısıyla kontrol edilmesini öneriyor. Test ortamı, bileşenleri üretim uygulamasında görünecekleri gibi işler ve ardından bunlarla bir kullanıcı olarak etkileşime girerek çeşitli olayları tetikler ve işlenmiş yapılar üzerindeki etkilerini test eder. Bir arka uç arabirimiyle iletişim kurmak gibi tipik olarak hizmetlerden soyutlanan görevler, bir HTTP istemci simülasyonu kullanılarak sistem sınırlarında test edilebilir.

Ve bundan ne öğreniyoruz?


Bağımlılık enjeksiyonu, Angular veya Nest gibi çerçeveler sayesinde JavaScript dünyasında da kendini kanıtlamış bir tasarım modelidir. Ancak her ortam için uygun değildir. Sınıf odaklı uygulamalarda güçlü yönlerini çok iyi oynayabildiği durumlarda, DI’nin işlevsel bir yaklaşımda kullanımı biraz sorgulanabilir. Doğru ortamda kullanıldığında DI, bağımsız birimlerin test edilmesini büyük ölçüde basitleştirir ve yapıların ayrışmasını sağlar, bu da uygulamanın ayrı parçalarını değiştirirken faydalıdır.


()



ana sayfaya
 
Üst