JavaRush /Java-Blog /Random-DE /Eine einfache Möglichkeit, Abhängigkeiten einzufügen

Eine einfache Möglichkeit, Abhängigkeiten einzufügen

Veröffentlicht in der Gruppe Random-DE
Dependency Injection (DI) ist kein leicht zu verstehendes Konzept und die Anwendung auf neue oder bestehende Anwendungen ist noch verwirrender. Jess Smith zeigt Ihnen, wie Sie eine Abhängigkeitsinjektion ohne Injektionscontainer in den Programmiersprachen C# und Java durchführen. Einfache Art der Abhängigkeitsinjektion – 1In diesem Artikel zeige ich Ihnen, wie Sie die Abhängigkeitsinjektion (DI) in .NET- und Java-Anwendungen implementieren. Das Konzept der Abhängigkeitsinjektion wurde Entwicklern erstmals im Jahr 2000 bekannt, als Robert Martin den Artikel „Design Principles and Patterns“ (später bekannt unter dem Akronym SOLID ) schrieb. Das D in SOLID bezieht sich auf Dependency of Inversion (DOI), das später als Dependency Injection bekannt wurde. Die ursprüngliche und gebräuchlichste Definition: Abhängigkeitsumkehr ist eine Umkehrung der Art und Weise, wie eine Basisklasse Abhängigkeiten verwaltet. In Martins Originalartikel wurde der folgende Code verwendet, um die Abhängigkeit einer Klasse Copyvon einer Klasse niedrigerer Ebene zu veranschaulichen WritePrinter:
void Copy()
	{
	 int c;
	 while ((c = ReadKeyboard()) != EOF)
		WritePrinter(c);
	}
Das erste offensichtliche Problem besteht darin, dass Sie, wenn Sie die Parameterliste oder die Typen einer Methode ändern WritePrinter, Aktualisierungen überall dort implementieren müssen, wo eine Abhängigkeit von dieser Methode besteht. Dieser Prozess erhöht die Wartungskosten und ist eine potenzielle Quelle neuer Fehler.
Möchten Sie etwas über Java lesen? Treten Sie der Java-Entwicklergruppe bei !
Ein weiteres Problem: Die Copy-Klasse ist kein potenzieller Kandidat mehr für die Wiederverwendung. Was passiert beispielsweise, wenn Sie über die Tastatur eingegebene Zeichen in einer Datei statt auf einem Drucker ausgeben müssen? Dazu können Sie die Klasse Copywie folgt ändern (C++-Sprachsyntax):
void Copy(outputDevice dev)
	{
	int c;
	while ((c = ReadKeyboard()) != EOF)
		if (dev == printer)
			WritePrinter(c);
		else
			WriteDisk(c);
	}
Trotz der Einführung einer neuen Abhängigkeit WriteDiskhat sich die Situation nicht verbessert (sondern eher verschlechtert), da ein weiterer Grundsatz verletzt wurde: „Software-Entitäten, also Klassen, Module, Funktionen usw., sollten für Erweiterungen offen, für Erweiterungen jedoch geschlossen sein.“ Änderung." Martin erklärt, dass diese neuen bedingten if/else-Anweisungen die Stabilität und Flexibilität des Codes verringern. Die Lösung besteht darin, die Abhängigkeiten umzukehren, sodass die Schreib- und Lesemethoden von der Copy. Anstatt Abhängigkeiten zu „platzen“, werden sie durch den Konstruktor geleitet. Der geänderte Code sieht so aus:
class Reader
	{
		public:
		virtual int Read() = 0;
	};
	class Writer
	{
		public:
		virtual void Write(char) = 0;
	};
	void Copy(Reader& r, Writer& w)
	{
		int c;
		while((c=r.Read()) != EOF)
		w.Write(c);
	}
Jetzt kann die Klasse Copyproblemlos mit verschiedenen Implementierungen von Klassenmethoden Readerund wiederverwendet werden Writer. Die Klasse Copyverfügt über keine Informationen über die interne Struktur der Typen Readerund Writer, sodass sie mit verschiedenen Implementierungen wiederverwendet werden können. Aber wenn Ihnen das alles wie eine Art Kauderwelsch vorkommt, werden die folgenden Beispiele in Java und C# vielleicht die Situation klären.

Beispiel in Java und C#

Um die Einfachheit der Abhängigkeitsinjektion ohne Abhängigkeitscontainer zu veranschaulichen, beginnen wir mit einem einfachen Beispiel, das DIin nur wenigen Schritten für die Verwendung angepasst werden kann. Nehmen wir an, wir haben eine Klasse HtmlUserPresentation, die beim Aufruf ihrer Methoden eine HTML-Benutzeroberfläche generiert. Hier ist ein einfaches Beispiel:
HtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Jedes Projekt, das diesen Klassencode verwendet, weist eine Abhängigkeit von der Klasse auf HtmlUserPresentation, was zu den oben beschriebenen Problemen bei der Benutzerfreundlichkeit und Wartbarkeit führt. Eine Verbesserung bietet sich sofort an: Erstellen einer Schnittstelle mit Signaturen aller derzeit in der Klasse verfügbaren Methoden HtmlUserPresentation. Hier ist ein Beispiel dieser Schnittstelle:
public interface IHtmlUserPresentation {
	String createTable(ArrayList rowVals, String caption);
	String createTableRow(String tableCol);
	// Оставшиеся сигнатуры
}
Nachdem wir die Schnittstelle erstellt haben, ändern wir die Klasse, HtmlUserPresentationum sie zu verwenden. Zurück zur Instanziierung des Typs HtmlUserPresentation: Wir können jetzt den Schnittstellentyp anstelle des Basistyps verwenden:
IHtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Durch die Erstellung einer Schnittstelle können wir problemlos andere Implementierungen von verwenden IHtmlUserPresentation. Wenn wir diesen Typ beispielsweise testen möchten, können wir den Basistyp problemlos HtmlUserPresentationdurch einen anderen Typ namens ersetzen HtmlUserPresentationTest. Die bisher vorgenommenen Änderungen erleichtern das Testen, Warten und Skalieren des Codes, tragen jedoch nicht zur Wiederverwendung bei, da alle HtmlUserPresentationKlassen, die den Typ verwenden, weiterhin über seine Existenz informiert sind. Um diese direkte Abhängigkeit zu entfernen, können Sie einen Schnittstellentyp IHtmlUserPresentationan den Konstruktor (oder die Liste der Methodenparameter) der Klasse oder Methode übergeben, die ihn verwenden wird:
public UploadFile(IHtmlUserPresentation htmlUserPresentation)
Der Konstruktor UploadFilehat nun Zugriff auf die gesamte Funktionalität des Typs IHtmlUserPresentation, weiß jedoch nichts über die interne Struktur der Klasse, die diese Schnittstelle implementiert. In diesem Zusammenhang erfolgt die Typinjektion, wenn eine Instanz der Klasse erstellt wird UploadFile. Ein Schnittstellentyp IHtmlUserPresentationwird wiederverwendbar, indem unterschiedliche Implementierungen an unterschiedliche Klassen oder Methoden übergeben werden, die unterschiedliche Funktionen erfordern.

Fazit und Empfehlungen zur Konsolidierung des Materials

Sie haben etwas über die Abhängigkeitsinjektion gelernt und erfahren, dass Klassen direkt voneinander abhängig sind, wenn eine von ihnen eine andere instanziiert, um Zugriff auf die Funktionalität des Zieltyps zu erhalten. Um die direkte Abhängigkeit zwischen den beiden Typen zu entkoppeln, sollten Sie eine Schnittstelle erstellen. Eine Schnittstelle gibt einem Typ die Möglichkeit, je nach Kontext der erforderlichen Funktionalität unterschiedliche Implementierungen einzuschließen. Durch die Übergabe eines Schnittstellentyps an einen Klassenkonstruktor oder eine Methode kennt die Klasse/Methode, die die Funktionalität benötigt, keine Details über den Typ, der die Schnittstelle implementiert. Aus diesem Grund kann ein Schnittstellentyp in verschiedenen Klassen wiederverwendet werden, die ein ähnliches, aber nicht identisches Verhalten erfordern.
  • Um mit der Abhängigkeitsinjektion zu experimentieren, schauen Sie sich Ihren Code aus einer oder mehreren Anwendungen an und versuchen Sie, einen häufig verwendeten Basistyp in eine Schnittstelle umzuwandeln.

  • Ändern Sie die Klassen, die diesen Basistyp direkt instanziieren, so, dass sie diesen neuen Schnittstellentyp verwenden, und übergeben Sie ihn über den Konstruktor oder die Parameterliste der Klassenmethode, die ihn verwenden wird.

  • Erstellen Sie eine Testimplementierung, um diesen Schnittstellentyp zu testen. Sobald Ihr Code umgestaltet ist, DIlässt er sich einfacher implementieren und Sie werden feststellen, wie viel flexibler Ihre Anwendung in Bezug auf Wiederverwendung und Wartbarkeit wird.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION