Bei der Entwicklung mit Laravel bin ich auf einen DI-Container gestoßen, und ich dachte, ich hätte DI während der Entwicklung mit Rails nie verwendet. Daher werde ich zusammenfassen, warum DI in Ruby (Rails) nicht häufig vorkommt.
TL;DR ――Da Ruby die Abhängigkeit von der Instanz dynamisch ändern kann, ist DI grundsätzlich nicht erforderlich. ―― Lesen Sie fast den folgenden Artikel. Wenn Sie also Englisch sprechen können, lesen Sie bitte diesen Artikel. LEGOs, Play-Doh, and Programming
DI DI (Dependency Injection) ist eine Technologie, die die Abhängigkeit zwischen Instanzen beseitigt, die als Abhängigkeitsinjektion bezeichnet werden. Es ist praktisch, Scheinobjekte während des Tests zu ersetzen, da Sie abhängige Instanzen von außen einfügen können. Das DI-Framework ist eine Technik, die lose Kopplung und hohe Aggregation realisiert, indem der DI-Container Instanzen erstellen und injizieren lässt. Es gibt einige DI-Frameworks, die häufig für native Apps verwendet werden (ich kenne iOS nicht). Nehmen wir also Java als Beispiel.
Java
public class A {
//Die B-Instanz wird in A generiert und der Verbindungsgrad ist hoch
public Client client = new B();
}
interface Client {
String outputSelf();
}
public class B implements Client {
@Override
public String outputSelf() {
return "B";
}
}
public class C implements Client {
@Override
public String outputSelf() {
return "C";
}
}
DI löst dieses Problem, und es gibt verschiedene Typen. Am Beispiel der Konstruktorinjektion sieht es jedoch wie folgt aus. A verliert die Substanz von B und wird lose gekoppelt.
public class A {
public Client client;
public void A(Client client) {
this.client = client;
}
}
In diesem Fall ist der Aufrufer jedoch dafür verantwortlich, die Instanz zu erstellen, die in A eingefügt werden soll, und die Verantwortlichkeiten werden verteilt. Wenn Sie also den DI-Container (z. B. Dagger2) verwenden, sieht dies folgendermaßen aus. Der DI-Container ist für das Injizieren der Abhängigkeit von der Aktivität verantwortlich, einschließlich A.
public class A {
public Client client;
@Inject
public void A(Client client) {
this.client = client;
}
}
Ruby Wie bisher erläutert, erleichtert DI das Ersetzen von Objekten, indem es von der Schnittstelle anstelle der konkreten Klasse (Instanz) abhängig gemacht wird. Was bedeutet es dann als Schlussfolgerung am Anfang, dass ein Mechanismus wie ein DI-Container in Ruby nicht erforderlich ist? Selbst wenn Sie eine Injektion durchführen möchten, können Sie mit der ursprünglichen Sprachfunktion von Ruby eine ausreichend lockere Kopplung und eine hohe Aggregation erreichen. Es scheint, dass die Verwendung eines DI-Containers nur die Komplexität erhöhen kann.
Wie im Java-Beispiel sieht es wie folgt aus, wenn eine Konstruktorinjektion durchgeführt wird.
class A
def initialize(options={})
@client_impl = options[:client] || B
end
def new_client
@client_impl.new
end
end
class B end
class C end
Reflection Eine Technologie, die die Struktur des Programms selbst während der Ausführung des Programms liest oder neu schreibt. In diesem Artikel handelt es sich um eine Methode zum dynamischen Umschreiben der Entität des Clients, der Mitglied der Klasse A ist, von außen.
Ruby
Der ursprüngliche Artikel besagt, dass Ruby die folgende Sprache ist.
The very Ruby language itself is designed for this: closures, super-simple introspection of objects, runtime modification of existing objects, and the use of modules for extending classes and objects all tend to result in an environment that is simple, malleable, and extensible.
Wenn Sie also dynamisch wie Ruby schreiben,
class A
def new_client
client.new
end
def client
B
end
end
class B end
class C end
Sogar die erstellte Instanz kann leicht geändert werden.
#Die Instanzmethode kann dynamisch geändert werden
def A.new.client
C
end
Java Reflection wird auch in Java unterstützt, sodass Sie die Mitglieder der Instanz wie folgt ersetzen können, aber ...
class D {
public static void main(String args[]){
try {
A a_instance = new A();
Class a = a_instance.getClass();
Field field = a.getDeclaredField("client");
System.out.println("before reflection:" + ((Client) field.get(a_instance)).outputSelf());
field.setAccessible(true);
field.set(a_instance, new C());
System.out.println("after reflection:" + ((Client) field.get(a_instance)).outputSelf());
} catch (Exception e) {}
}
}
Im Vergleich zur Injektion ist es überwiegend schwer zu verstehen und die Komplexität nimmt zu.
Ruby ist dynamischer als Sprachen wie Java, und selbst wenn es einmal erstellt wurde, ist es einfach, Abhängigkeiten zu ändern und zu ändern. Daher scheint die Einführung eines Mechanismus wie eines DI-Containers, der in einer statischen Sprache erforderlich war, die Komplexität nur zu erhöhen.
Recommended Posts