Bağımlılık enjeksiyonu - Dependency injection

Gelen yazılım mühendisliği , bağımlılık enjeksiyon bir edildiği bir tekniktir nesne o denilen bağımlılıkları bağlı olduğunu diğer nesneleri alır. Tipik olarak, alıcı nesneye istemci , iletilen ('enjekte edilen') nesneye ise hizmet adı verilir . Hizmeti istemciye ileten koda enjektör denir. İstemcinin hangi hizmeti kullanacağını belirtmek yerine, enjektör istemciye hangi hizmeti kullanacağını söyler. 'Enjeksiyon', bir bağımlılığın (hizmetin) onu kullanan istemciye iletilmesi anlamına gelir.

Hizmet, müşterinin durumunun bir parçası haline getirilir . Bir istemcinin hizmeti oluşturmasına veya bulmasına izin vermek yerine hizmeti istemciye geçirmek , modelin temel gereksinimidir.

Bağımlılık enjeksiyonunun arkasındaki amaç , nesnelerin inşası ve kullanımı ile ilgili endişelerin ayrılmasını sağlamaktır . Bu, okunabilirliği ve kodun yeniden kullanımını artırabilir.

Bağımlılık enjeksiyonu, kontrolü tersine çevirmenin daha geniş tekniğinin bir biçimidir . Bazı hizmetleri aramak isteyen bir müşteri, bu hizmetleri nasıl oluşturacağını bilmek zorunda değildir. Bunun yerine, istemci harici koda (enjektör) yetki verir. Müşteri enjektörün farkında değil. Enjektör, mevcut veya enjektörün kendisi tarafından oluşturulabilecek hizmetleri müşteriye iletir. İstemci daha sonra hizmetleri kullanır.

Bu, müşterinin enjektörü, hizmetlerin nasıl oluşturulacağını ve hatta hangi hizmetleri gerçekten kullandığını bilmesine gerek olmadığı anlamına gelir. İstemcinin yalnızca hizmetlerin arayüzlerini bilmesi gerekir, çünkü bunlar müşterinin hizmetleri nasıl kullanabileceğini tanımlar. Bu, 'kullanım' sorumluluğunu 'inşaat' sorumluluğundan ayırır.

genel bakış

Beş yaşındakiler için bağımlılık enjeksiyonu

Gidip kendiniz için buzdolabından bir şeyler aldığınızda, sorunlara neden olabilirsiniz. Kapıyı açık bırakabilirsin, annen ya da baban almanı istemediği bir şey alabilirsin. Hatta bizde olmayan veya süresi dolmuş bir şeyi arıyor bile olabilirsiniz.

Yapmanız gereken şey, "Öğle yemeğinin yanında içecek bir şeye ihtiyacım var" şeklinde bir ihtiyaç belirtmek ve sonra yemek için oturduğunuzda bir şeyler olduğundan emin olacağız.

John Munsch, 28 Ekim 2009.

Bağımlılık ekleme aşağıdaki sorunları çözer:

  • Bir sınıf , bağımlı olduğu nesnelerin nasıl yaratıldığından bağımsız olabilir ?
  • Nesnelerin oluşturulma şekli ayrı yapılandırma dosyalarında nasıl belirtilebilir?
  • Bir uygulama farklı konfigürasyonları nasıl destekleyebilir?

Doğrudan sınıf içinde nesneler oluşturmak, sınıfı belirli uygulamalara bağlar. Bu, özellikle temel alınan nesnelerin değiştirilmesinin kaynak kodun yeniden derlenmesini gerektirebileceği derlenmiş dillerde, çalışma zamanında örneğini değiştirmeyi zorlaştırır.

Bağımlılık enjeksiyonu, istemcinin bağımlılıklarının oluşturulmasını istemcinin gevşek bağlı programları ve bağımlılığı tersine çevirme ve tek sorumluluk ilkelerini destekleyen davranışından ayırır . Temel olarak, bağımlılık enjeksiyonu, parametreleri bir metoda geçirmeye dayanır .

Bağımlılık enjeksiyonu, kontrolün tersine çevrilmesinin daha genel kavramına bir örnektir .

Bağımlılık enjeksiyonu olmadan kontrolün tersine çevrilmesine bir örnek, polimorfizmin alt sınıflama yoluyla elde edildiği şablon yöntem modelidir . Bağımlılık enjeksiyonu, kompozisyon yoluyla kontrolün tersine çevrilmesini uygular ve genellikle strateji modeline benzer . Strateji modeli, bir nesnenin ömrü boyunca değiştirilebilir olan bağımlılıklar için tasarlanırken , bağımlılık enjeksiyonunda yalnızca tek bir bağımlılığın örneğinin kullanılması olabilir. Bu yine de polimorfizmi başarır, ancak delegasyon ve kompozisyon yoluyla .

Bağımlılık ekleme , istemcilerin bağımlılıkları bulmak için kullandıkları sistem hakkında bilgi sahibi olmalarını sağlayan hizmet bulucu modeliyle doğrudan çelişir .

Roller

Bağımlılık enjeksiyonu dört rol içerir:

  • kullanılacak hizmet nesneleri
  • İstemci olan davranış nesne, kullandığı hizmetlere bağlıdır
  • arayüzleri , istemci hizmetlerini kullanmak nasıl tanımlamak
  • hizmetleri oluşturan ve bunları istemciye enjekte eden enjektör

Bir benzetme olarak,

  • servis - elektrikli, gazlı, hibrit veya dizel araba
  • müşteri - motordan bağımsız olarak arabayı aynı şekilde kullanan bir sürücü
  • arayüz - sürücünün vites değiştirme ayrıntılarını anlamasını gerektirmeyen otomatik şanzıman
  • enjektör - arabayı sürücü için satın alan ve hangi tür olduğuna karar veren ebeveyn

Kullanılabilecek herhangi bir nesne bir hizmet olarak kabul edilebilir . Diğer nesneleri kullanan herhangi bir nesne, bir istemci olarak kabul edilebilir . İsimler yalnızca nesnelerin bir enjeksiyonda oynadığı rolle ilgilidir.

Arayüzleri istemci bağımlılıkları olmasını beklediğini türleridir. İstemci, bağımlılıklarının özel uygulamasını bilmemeli, yalnızca arabirimin adını ve API'sini bilmelidir . Sonuç olarak, arayüzün arkasında ne olduğu değişse bile istemcinin değişmesi gerekmeyecektir. Bağımlılık ekleme, gerçek arabirimler veya soyut sınıflarla değil, aynı zamanda somut hizmetlerle de çalışabilir , ancak bu , bağımlılığı tersine çevirme ilkesini ihlal eder ve test etmeyi sağlayan dinamik ayrıştırmayı feda eder . Yalnızca müşterinin arayüzlerini inşa ederek veya genişleterek asla somut olarak görmemesi gerekir. Arabirim ise tekrar elden bir arayüz tipi (veya tersi) bir sınıftan istemci yeniden derlenmesi gerekir. İstemci ve hizmetler ayrı ayrı yayınlanıyorsa bu önemlidir.

Enjektör müşteriye hizmet tanıtır. Çoğu zaman, aynı zamanda istemciyi de oluşturur. Bir enjektör, aynı nesneyi hem bir noktada istemci hem de başka bir noktada hizmet olarak ele alarak karmaşık bir nesne grafiğini bağlayabilir. Enjektörün kendisi aslında birlikte çalışan birçok nesne olabilir, ancak istemci olmayabilir (bu döngüsel bir bağımlılık yaratacağından ). Enjektör, bir montajcı, sağlayıcı, konteyner, fabrika, inşaatçı, yay veya inşaat kodu olarak adlandırılabilir.

Bir disiplin olarak, bağımlılık enjeksiyonu, tüm nesnelerin yapı ve davranışı ayırmasını ister. Oluşturmak için bir DI çerçevesine güvenmek, newanahtar kelimenin yasaklanmasına veya daha az katı bir şekilde yalnızca değer nesnelerinin doğrudan oluşturulmasına izin verilmesine yol açabilir .

Yapı

Image
Dependency Injection tasarım modeli için örnek bir UML sınıfı ve sıra diyagramı.

Yukarıda UML sınıf diyagramı , Clientsınıf gerektirir ServiceAve ServiceBancak örneğini etmez ServiceA1ve ServiceB1nesneleri doğrudan.

Bunun yerine, bir Injectorsınıf nesneleri oluşturur ve bunları Client. ClientSınıflar örneği olan bağımsızdır. UML sırası diyagramı doğru gösterir çalıştırma etkileşimlerini:

  1. InjectorNesne oluşturur ServiceA1ve ServiceB1nesneleri.
  2. InjectorOluşturur Clientnesne.
  3. InjectorEnjekte eder ServiceA1ve ServiceB1içine nesneler Clientnesne.

Avantajlar ve dezavantajlar

Avantajlar

Bağımlılık eklemenin temel bir yararı, sınıflar ve bağımlılıkları arasındaki bağlantının azalmasıdır. Bir müşterinin bağımlılıklarının nasıl uygulandığına dair bilgisini ortadan kaldırarak programlar daha yeniden kullanılabilir, test edilebilir ve sürdürülebilir hale gelir.

Bu aynı zamanda esnekliğin artmasıyla da sonuçlanır: bir müşteri, beklediği içsel arabirimi destekleyen herhangi bir şey üzerinde hareket edebilir.

Bağımlılık eklemenin faydalarının çoğu, özellikle birim testiyle ilgilidir .

Örneğin, bir sistemin yapılandırma ayrıntılarını yapılandırma dosyalarına dışsallaştırmak için bağımlılık enjeksiyonu kullanılabilir ve bu da sistemin yeniden derleme olmadan yeniden yapılandırılmasına olanak tanır. Bileşenlerin farklı uygulamalarını gerektiren farklı durumlar için ayrı konfigürasyonlar yazılabilir. Buna test dahildir. Benzer şekilde, bağımlılık ekleme, kod davranışında herhangi bir değişiklik gerektirmediğinden, eski koda yeniden düzenleme olarak uygulanabilir . Sonuç, daha bağımsız olan ve test edilmeyen diğer nesneleri simüle eden saplamalar veya sahte nesneler kullanarak ayrı ayrı birim testi yapması daha kolay olan istemcilerdir . Bu test kolaylığı, genellikle bağımlılık enjeksiyonu kullanılırken fark edilen ilk faydadır.

Daha genel olarak, bağımlılık ekleme , tüm bağımlılık oluşturma tek bir bileşen tarafından gerçekleştirildiğinden, ortak kod kodunu azaltır .

Son olarak, bağımlılık enjeksiyonu eşzamanlı geliştirmeye izin verir. İki geliştirici, yalnızca sınıfların iletişim kuracağı arabirimi bilmeye ihtiyaç duyarken, birbirini kullanan sınıfları bağımsız olarak geliştirebilir . Eklentiler genellikle, eklentileri kullanan ürünü oluşturan geliştiricilerle hiç konuşmayan üçüncü taraf mağazalar tarafından geliştirilir.

Dezavantajları

Bağımlılık enjeksiyonunun eleştirileri şunu iddia ediyor:

  • Belirgin varsayılanlar mevcut olduğunda zahmetli olabilecek yapılandırma ayrıntılarını talep eden istemciler oluşturur.
  • Davranışı yapıdan ayırdığı için kodun izlenmesini zorlaştırın.
  • Genellikle yansıma veya dinamik programlama ile uygulanır. Bu, IDE otomasyonunu engelleyebilir .
  • Tipik olarak daha fazla ön geliştirme çabası gerektirir.
  • Karmaşıklığı sınıfların dışına ve yönetilmesi daha zor olabilecek sınıflar arasındaki bağlantılara zorlar.
  • Bir çerçeveye bağımlılığı teşvik edin.

Bağımlılık enjeksiyonu türleri

Bir müşterinin harici bir modüle referans almasının en az üç yolu vardır:

  • Yapıcı enjeksiyonu: Bağımlılıklar, bir müşterinin sınıf kurucusu aracılığıyla sağlanır.
  • Ayarlayıcı enjeksiyonu: İstemci, enjektörün bağımlılığı enjekte etmek için kullandığı bir ayarlayıcı yöntemi sunar.
  • Arayüz enjeksiyonu: Bağımlılığın arayüzü, kendisine geçirilen herhangi bir istemciye bağımlılığı enjekte edecek bir enjektör yöntemi sağlar.

DI çerçeveleri ve test çerçeveleri, diğer enjeksiyon türlerini kullanabilir.

Bazı modern test çerçeveleri, istemcilerin bağımlılık enjeksiyonunu aktif olarak kabul etmesini bile gerektirmez, böylece eski kodu test edilebilir hale getirir . In Java test ederken, yansıma gizli özellikleridir herkese açık hale getirebilir ve böylece atama yoluyla enjeksiyonları kabul edin.

Kontrolün Tersine Çevirilmesindeki bazı girişimler, basitçe bir bağımlılık biçimini diğerinin yerine koyar . Genel bir kural olarak, bir programcı istemci kodundan başka bir şeye bakamıyorsa ve hangi çerçevenin kullanıldığını söyleyebiliyorsa, istemcinin çerçeveye sabit kodlanmış bir bağımlılığı vardır.

Bağımlılık enjeksiyonu olmadan

Aşağıdaki Java örneğinde, Clientsınıf , yapıcıda başlatılan bir Service üye değişken içerir . Müşteri, hangi hizmetin kullanıldığını ve yapısını kontrol eder. İstemci, üzerinde sabit kodlanmış bir bağımlılığa sahiptir . ExampleService

public class Client {
    // Internal reference to the service used by this client
    private ExampleService service;

    // Constructor
    Client() {
        // Specify a specific implementation instead of using dependency injection
        service = new ExampleService();
    }

    // Method that uses the services
    public String greet() {
        return "Hello " + service.getName();
    }
}

Bu örneği aşağıda açıklanan teknikleri kullanarak ayarlayabiliriz.

Yapıcı enjeksiyon

Bu yöntem, istemcinin bağımlılık için yapıcıda bir parametre sağlamasını gerektirir . Bu, bazı bağımlılıklarının boş veya ayarlanmamış olmasının aksine, istemci nesnesinin her zaman geçerli bir durumda olmasını sağlar. Bu, istemciyi değişmez ve dolayısıyla iş parçacığı güvenli hale getirmeye yönelik ilk adım olabilir . Ancak, kendi başına bu model, bağımlılıklarını daha sonra değiştirme esnekliğinden yoksundur.

// Constructor
Client(Service service, Service otherService) {
    if (service == null) {
        throw new InvalidParameterException("service must not be null");
    }
    if (otherService == null) {
        throw new InvalidParameterException("otherService must not be null");
    }

    // Save the service references inside this client
    this.service = service;
    this.otherService = otherService;
}

Setter enjeksiyonu

Bu yöntem, istemcinin bağımlılık için bir ayarlayıcı yöntemi sağlamasını gerektirir . Enjektörler daha sonra herhangi bir zamanda bağımlılık referanslarını değiştirebilir.

Bu esneklik sağlar, ancak istemci kullanılmadan önce tüm bağımlılıkların enjekte edilmesini sağlamak zordur. Bu enjeksiyonlar bağımsız olarak gerçekleştiğinden, enjektörün ayarlayıcısını çağırmaması nedeniyle bir bağımlılık boş bırakılabilir. Buna karşılık, bir kurucuda bildirilen bir bağımlılık, bağımlılık sağlanmadıkça bir nesnenin inşa edilemeyeceği anlamına gelir.

Aşağıdaki örnek, bir istemcinin kullanıldığında enjeksiyonun tamamlandığını kontrol etmesinin bir yolunu gösterir.

// Set the service to be used by this client
public void setService(Service service) {
    this.service = service;
}

// Set the other service to be used by this client
public void setOtherService(Service otherService) {
    this.otherService = otherService;
}

// Check the service references of this client
private void validateState() {
    if (service == null) {
        throw new IllegalStateException("service must not be null");
    }
    if (otherService == null) {
        throw new IllegalStateException("otherService must not be null");
    }
}

// Method that uses the service references
public void doSomething() {
    validateState();
    service.doYourThing();
    otherService.doYourThing();
}

Arayüz enjeksiyonu

Arayüz enjeksiyonu ile, bağımlılıklar istemcilerinden tamamen habersiz olabilir, ancak yine de yeni istemcilere referanslar gönderip alabilir.

Bu şekilde, bağımlılıklar enjektör haline gelir. Anahtar, enjekte etme yönteminin (sadece bir ayarlayıcı yöntem olabilir) bir arabirim aracılığıyla sağlanmasıdır.

İstemciyi ve bağımlılıklarını tanıtmak için hala bir montajcıya ihtiyaç vardır. Montajcı, istemciye bir referans alır, onu bu bağımlılığı ayarlayan ayarlayıcı arabirimine atar ve onu, kendi kendine bir referansı istemciye geri ileten bu bağımlılık nesnesine iletir.

Arayüz enjeksiyonunun değere sahip olması için, bağımlılığın kendisine bir referansı geri göndermeye ek olarak bir şeyler yapması gerekir. Bu, diğer bağımlılıkları çözmek için bir fabrika veya alt montajcı gibi davranabilir, böylece ana montajcıdan bazı ayrıntıları soyutlayabilir. Bağımlılığın onu kaç müşterinin kullandığını bilmesi için referans sayımı olabilir. Bağımlılık bir istemci koleksiyonunu koruyorsa, daha sonra hepsine kendisinin farklı bir örneğini enjekte edebilir.

// Service setter interface.
public interface ServiceSetter {
    public void setService(Service service);
}

// Client class
public class Client implements ServiceSetter {
    // Internal reference to the service used by this client.
    private Service service;

    // Set the service that this client is to use.
    @Override
    public void setService(Service service) {
        this.service = service;
    }
}

// Injector class
public class ServiceInjector {
	Set<ServiceSetter> clients;
	public void inject(ServiceSetter client) {
		clients.add(client);
		client.setService(new ServiceFoo());
	}
	public void switchToBar() {
		for (Client client : clients) {
			client.setService(new ServiceBar());
		}
	}
}

// Service classes
public class ServiceFoo implements Service {}
public class ServiceBar implements Service {}

toplantı

Bağımlılık eklemeyi uygulamanın en basit yolu, genellikle programın yürütülmeye başladığı "kök" kısmında yapılan hizmetleri ve istemcileri manuel olarak düzenlemektir.

public class Injector {
    public static void main(String[] args) {
        // Build the dependencies first
        Service service = new ExampleService();

        // Inject the service, constructor style
        Client client = new Client(service);

        // Use the objects
        System.out.println(client.greet());
    }	
}

Yukarıdaki örnek, nesne grafiğini manuel olarak oluşturur ve ardından onu çağırır. Bu enjektör, oluşturduğu nesnelerden birini kullandığı için 'saf' değildir ( Client).

Manuel inşaat daha karmaşık olabilir ve inşaatçılar , fabrikalar veya diğer inşaat modellerini içerebilir .

çerçeveler

.NET Framework'te bağımlılık ekleme kapsayıcılarının sınıf diyagramı.
Ninject veya Structure map gibi kapsayıcılar , kontrolün tersine çevrilmesini sağlamak için nesne yönelimli programlama dillerinde yaygın olarak kullanılır .

Yapı kodu artık uygulamaya özel olmadığında ve bunun yerine evrensel olduğunda, manuel bağımlılık enjeksiyonu bir bağımlılık enjeksiyon çerçevesi haline gelir .

Uygulama çerçeveleri gibi Weld , Bahar , Guice , Çal çerçevesinde , Salta , Glassfish hK2 , Hançer ve Yönetilen Extensibility Framework desteği bağımlılık enjeksiyon ama bağımlılık enjeksiyon yapmak gerekli değildir.

Spring gibi çerçeveler , istemciye bir referans döndürmeden önce nesneler oluşturabilir ve bunları birbirine bağlayabilir. Spring gibi çerçeveler, yapılandırma dosyalarında montaj ayrıntılarının dışsallaştırılmasına izin verdiğinden, betonun tüm sözleri ExampleServicekoddan yapılandırma verilerine taşınabilir:

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Injector {
	public static void main(String[] args) {
		// -- Assembling objects -- //
		BeanFactory beanfactory = new ClassPathXmlApplicationContext("Beans.xml");
		Client client = (Client) beanfactory.getBean("client");

		// -- Using objects -- //
		System.out.println(client.greet());
	}
}

Uzun ve karmaşık bir nesne grafiğiyle bile, kodda belirtilen tek sınıf, bu durumda giriş noktasıdır Client.

 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="service" class="ExampleService">
    </bean>

    <bean id="client" class="Client">
        <constructor-arg value="service" />        
    </bean>
</beans>

Clientve ServiceSpring ile çalışmak ve POJO olarak kalmak için herhangi bir değişiklik yapılmamıştır . Spring, varlığından tamamen habersiz olan hizmetleri ve istemcileri birbirine bağlayabilir. Spring'e özgü ek açıklamaların ve çağrıların birçok sınıf arasında yayılmasını önleyerek, sistem Spring'e yalnızca gevşek bir şekilde bağımlı kalır.

POJO'ları saf tutmak çaba gerektirir. Karmaşık yapılandırma dosyalarını korumak yerine, sınıflar ek açıklamaları kullanarak Spring'in zor işi yapılandırma üzerinden kuralı kullanarak yapmasına izin verebilir .

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Injector {
	public static void main(String[] args) {
		// Assemble the objects
		BeanFactory beanfactory = new AnnotationConfigApplicationContext(MyConfiguration.class);
		Client client = beanfactory.getBean(Client.class);

		// Use the objects
		System.out.println(client.greet());
	}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ComponentScan
public class MyConfiguration {
    @Bean
    public Client client(ExampleService service) {
        return new Client(service);
    }
}
@Component
public class ExampleService {
    public String getName() {
        return "World!";
    }
}

Farklı enjektörler (fabrikalar, servis bulucular ve bağımlılık enjeksiyon kapları) esas olarak nerede kullanılabilecekleri konusunda farklılık gösterir. Çağrıları bir fabrikaya veya bir hizmet bulucuya istemciden ve program köküne taşımak, bir bağımlılık enjeksiyon kabı kullanmaya eşdeğerdir.

Enjektör bilgisi kaldırılarak, müşteri dış dünya bilgisinden kurtulur, geride bırakılır. Ancak, program kökünü içeren nesne de dahil olmak üzere, diğer nesneleri kullanan herhangi bir nesne bir istemci olarak kabul edilebilir. Sonuç olarak, mainyukarıdaki örnekte aslında servis bulucu deseni kullanılıyor. Bundan kaçınılamaz çünkü hizmet uygulamalarının seçimi bir yerde yapılmalıdır.

Örnekler

AngularJS

Gelen angularjs , doğrudan bağımlılıkları erişebilir sadece üç yolu bir bileşenidir (nesne veya fonksiyonu) vardır:

  1. Bileşen, tipik olarak newoperatörü kullanarak bağımlılığı oluşturabilir .
  2. Bileşen, global bir değişkene başvurarak bağımlılığı arayabilir.
  3. Bileşen, ihtiyaç duyulan yere bağımlılığın kendisine geçmesini sağlayabilir.

İlk iki seçenek, bileşene bağımlılığı sabit kodladıkları için optimal değildir. Bu, test izolasyonu için bağımlılıklarla alay etmenin genellikle istendiği testlerde sorunludur .

Üçüncü seçenek, bileşenden bağımlılığı bulma sorumluluğunu ortadan kaldırır.

function SomeClass(greeter) {
  this.greeter = greeter;
}

SomeClass.prototype.doSomething = function(name) {
  this.greeter.greet(name);
}

SomeClasssomutlaştırıldığında basitçe selamlayıcıya verilir. Bu, bağımlılık oluşturma sorumluluğunu oluşturan koda verir SomeClass.

Bunu yönetmek için her AngularJS uygulamasının bir 'enjektör'ü vardır: bağımlılıkların oluşturulmasından ve aranmasından sorumlu bir hizmet bulucu.

// Provide the wiring information in a module
var myModule = angular.module('myModule', []);

// Teach the injector how to build a greeter service. 
// greeter is dependent on the $window service. 
// The greeter service is an object that
// contains a greet method.
myModule.factory('greeter', function($window) {
  return {
    greet: function(text) {
      $window.alert(text);
    }
  };
});

Modülde tanımlanan bileşenleri sağlayabilecek yeni bir enjektör oluşturun ve enjektörden myModulekarşılama hizmetimizi talep edin.

var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');

Bağımlılık istemek, sabit kodlama sorununu çözer, ancak aynı zamanda enjektörün uygulama boyunca geçirilmesi gerektiği anlamına gelir. Enjektörü geçmek Demeter Yasasını çiğniyor . Bunu düzeltmek için HTML şablonlarımızda bileşen oluşturma sorumluluğunu enjektöre devretmek için bildirimsel bir gösterim kullanıyoruz:

<div ng-controller="MyController">
  <button ng-click="sayHello()">Hello</button>
</div>
function MyController($scope, greeter) {
  $scope.sayHello = function() {
    greeter.greet('Hello World');
  };
}

AngularJS HTML'yi derlerken, ng-controlleryönergeyi işler , bu da enjektörden denetleyicinin ve bağımlılıklarının bir örneğini oluşturmasını ister.

injector.instantiate(MyController);

Çünkü ng-controllerenjektör uygulamalara atıfta sınıf örneğini oluşturmak için, bu bağımlılıkları tatmin MyControllerenjektörünün bilerek kontrol olmadan. Uygulama kodu , Demeter Yasasını koruyarak ihtiyaç duyduğu bağımlılıkları bildirir .

C#

C# üzerinde Yapıcı enjeksiyonu , Setter enjeksiyonu ve Arayüz enjeksiyonu örneği

using System;

namespace DependencyInjection
{
    // An interface for the library
    interface IGamepadFunctionality
    {
        String GetGamepadName();
        void SetVibrationPower(float InPower);
    }

    // Concrete implementation of the xbox controller functionality
    class XBoxGamepad : IGamepadFunctionality
    {
        readonly String GamepadName = "XBox Controller";
        float VibrationPower = 1.0f;
        public String GetGamepadName() => GamepadName;
        public void SetVibrationPower(float InPower) => VibrationPower = Math.Clamp(InPower, 0.0f, 1.0f);

    }

    // Concrete implementation of the playstation controller functionality
    class PlaystationJoystick : IGamepadFunctionality
    {
        readonly String ControllerName = "Playstation controller";
        float VibratingPower = 100.0f;
        public String GetGamepadName() => ControllerName;
        public void SetVibrationPower(float InPower) => VibratingPower = Math.Clamp(InPower * 100.0f, 0.0f, 100.0f);
    }

    // Concrete implementation of the steam controller functionality
    class SteamController : IGamepadFunctionality
    {
        readonly String JoystickName = "Steam controller";
        double Vibrating = 1.0;
        public String GetGamepadName() => JoystickName;
        public void SetVibrationPower(float InPower) => Vibrating = Convert.ToDouble(Math.Clamp(InPower, 0.0f, 1.0f));
    }

    // An interface for gamepad functionality injections
    interface IGamepadFunctionalityInjector
    {
        void InjectFunctionality(IGamepadFunctionality InGamepadFunctionality);
    }

    class CGamepad : IGamepadFunctionalityInjector
    {
        IGamepadFunctionality _GamepadFunctionality;

        public CGamepad()
        {

        }
        // Constructor injection
        public CGamepad(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;

        // Setter injection
        public void SetGamepadFunctionality(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;

        // Interface injection
        public void InjectFunctionality(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;

        public void Showcase()
        {
            String Message = String.Format("We're using the {0} right now, do you want to change the vibrating power?\r\n", _GamepadFunctionality.GetGamepadName());
            Console.WriteLine(Message);
        }
    }

    enum EPlatforms: byte
    {
        Xbox,
        Playstation,
        Steam
    }

    class CGameEngine
    {
        EPlatforms _Platform;
        CGamepad _Gamepad;
        public void SetPlatform(EPlatforms InPlatform)
        {
            _Platform = InPlatform;
            switch(_Platform)
            {
                case EPlatforms.Xbox:

                    // injects dependency on XBoxGamepad class through Constructor Injection
                    _Gamepad = new CGamepad(new XBoxGamepad());
                    break;
                case EPlatforms.Playstation:
                    _Gamepad = new CGamepad();

                    // injects dependency on PlaystationJoystick class through Setter Injection
                    _Gamepad.SetGamepadFunctionality(new PlaystationJoystick());
                    break;
                case EPlatforms.Steam:
                    _Gamepad = new CGamepad();

                    // injects dependency on SteamController class through Interface Injection
                    _Gamepad.InjectFunctionality(new SteamController());
                    break;
            }

            _Gamepad.Showcase();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            
            CGameEngine Engine = new CGameEngine();

            Engine.SetPlatform(EPlatforms.Steam);

            Engine.SetPlatform(EPlatforms.Xbox);

            Engine.SetPlatform(EPlatforms.Playstation);
        }
    }
}

Ayrıca bakınız

Referanslar

Dış bağlantılar