Ich habe eine Reihe von angle2-Komponenten, die alle einen Service erhalten sollten. Mein erster Gedanke war, dass es am besten wäre, eine Superklasse zu schaffen und den Service dort zu injizieren. Jede meiner Komponenten würde dann diese Oberklasse erweitern, aber dieser Ansatz funktioniert nicht.
Vereinfachtes Beispiel:
export class AbstractComponent {
constructor(private myservice: MyService) {
// Inject the service I need for all components
}
}
export MyComponent extends AbstractComponent {
constructor(private anotherService: AnotherService) {
super(); // This gives an error as super constructor needs an argument
}
}
Ich könnte dies lösen, indem ich MyService
in jede einzelne Komponente einspritze und dieses Argument für den super()
Aufruf verwende, aber das ist definitiv eine Art Absurdität.
Wie organisiere ich meine Komponenten richtig, damit sie einen Service von der Superklasse erben?
new MyService()
anstelle der Injektion liefert genau das gleiche Ergebnis (außer effizienter). Wenn Sie dieselbe Dienstinstanz für verschiedene Dienste und / oder Komponenten freigeben möchten, funktioniert dies nicht. Jede Klasse erhält eine andereMyService
Instanz.myService
. Es wurde eine Lösung gefunden, die dies vermeidet, aber den abgeleiteten Klassen mehr Code hinzufügt ...Antworten:
Es ist nicht absurd. So funktionieren Konstruktoren und Konstruktorinjektion.
Jede injizierbare Klasse muss die Abhängigkeiten als Konstruktorparameter deklarieren. Wenn die Oberklasse auch Abhängigkeiten aufweist, müssen diese ebenfalls im Konstruktor der Unterklasse aufgelistet und mit dem
super(dep1, dep2)
Aufruf an die Oberklasse weitergeleitet werden .Das Umgeben eines Injektors und das Erwerben von Abhängigkeiten hat zwangsläufig schwerwiegende Nachteile.
Es verbirgt Abhängigkeiten, die das Lesen von Code erschweren.
Es verstößt gegen die Erwartungen eines Menschen, der mit der Funktionsweise von Angular2 DI vertraut ist.
Es unterbricht die Offline-Kompilierung, die statischen Code generiert, um deklarativen und imperativen DI zu ersetzen, um die Leistung zu verbessern und die Codegröße zu reduzieren.
quelle
super
als 20 Klassen CTOR-Injektionen (und die entsprechenden Anrufe) hinzufügen, und diese Zahl wird in Zukunft nur noch zunehmen. Also zwei Dinge: 1) Ich würde es hassen, wenn eine "große Codebasis" dies tun würde; und 2) Gott sei Dank für vimq
und vscodectrl+.
Die aktualisierte Lösung verhindert, dass mithilfe des globalen Injektors mehrere Instanzen von myService generiert werden.
Dadurch wird sichergestellt, dass MyService in jeder Klasse verwendet werden kann, die AbstractComponent erweitert, ohne dass MyService in jede abgeleitete Klasse eingefügt werden muss.
Diese Lösung hat einige Nachteile (siehe Kommentar von @ Günter Zöchbauer unter meiner ursprünglichen Frage):
Für eine sehr gut geschriebene Erklärung von Dependency Injection in Angular2 diese Blog - Post sehen , die mir sehr geholfen , das Problem zu lösen: http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular- 2.html
quelle
this.myServiceA = injector.get(MyServiceA);
etc sein?Injector
globale Erweiterung untersucht , um zu vermeiden, dass Parameter verkettet werden müssenAbstractComponent
? fwiw, ich denke, dass das Einfügen von Abhängigkeiten in eine weit verbreitete Basisklasse, um eine unordentliche Verkettung von Konstruktoren zu vermeiden, eine absolut gültige Ausnahme von der üblichen Regel ist.Anstatt alle Dienste manuell zu injizieren, habe ich eine Klasse erstellt, die die Dienste bereitstellt, z. B. werden die Dienste injiziert. Diese Klasse wird dann in die abgeleiteten Klassen eingefügt und an die Basisklasse weitergegeben.
Abgeleitete Klasse:
Basisklasse:
Dienstleistungsklasse:
quelle
Anstatt einen Dienst einzufügen, der alle anderen Dienste als Abhängigkeiten hat, wie folgt:
Ich würde diesen zusätzlichen Schritt überspringen und einfach alle Dienste in die BaseComponent einfügen, wie folgt:
Diese Technik setzt zwei Dinge voraus:
Ihr Anliegen bezieht sich ausschließlich auf die Vererbung von Komponenten. Der Grund, warum Sie auf diese Frage gestoßen sind, ist höchstwahrscheinlich die überwältigende Menge an nicht trockenem (WET?) Code, die Sie in jeder abgeleiteten Klasse wiederholen müssen. Wenn Sie die Vorteile eines einzigen Einstiegspunkts für alle Ihre Komponenten und Services nutzen möchten, müssen Sie den zusätzlichen Schritt ausführen.
Jede Komponente erweitert die
BaseComponent
Es gibt auch einen Nachteil, wenn Sie den Konstruktor einer abgeleiteten Klasse verwenden, da Sie
super()
alle Abhängigkeiten aufrufen und übergeben müssen. Obwohl ich keinen Anwendungsfall sehe, der die Verwendung vonconstructor
anstelle von erfordertngOnInit
, ist es durchaus möglich, dass ein solcher Anwendungsfall existiert.quelle
Wenn die übergeordnete Klasse vom Plug-In eines Drittanbieters stammt (und Sie die Quelle nicht ändern können), können Sie Folgendes tun:
oder am besten (nur ein Parameter im Konstruktor bleiben):
quelle
Soweit ich weiß, müssen Sie es zuerst instanziieren, um von der Basisklasse zu erben. Um es zu instanziieren, müssen Sie die vom Konstruktor erforderlichen Parameter übergeben, damit Sie sie über einen super () -Aufruf vom Kind zum Elternteil übergeben können, damit dies sinnvoll ist. Der Injektor ist natürlich eine weitere praktikable Lösung.
quelle
Hässlicher Hack
Vor einiger Zeit möchte ein Teil meines Kunden zwei große Winkelprojekte bis gestern verbinden (Winkel v4 in Winkel v8). Project v4 verwendet die BaseView-Klasse für jede Komponente und enthält eine
tr(key)
Methode für Übersetzungen (in v8 verwende ich ng-translate). Um zu vermeiden, dass das Übersetzungssystem gewechselt und Hunderte von Vorlagen (in Version 4) bearbeitet oder das Übersetzungssystem 2 parallel eingerichtet werden, verwende ich folgenden hässlichen Hack (ich bin nicht stolz darauf) - in derAppModule
Klasse füge ich folgenden Konstruktor hinzu:und jetzt können
AbstractComponent
Sie verwendenquelle