This is the sixth day of my participation in the August Text Challenge.More challenges in August

Why dependency injection

In traditional coding, if we need an object, we usually create one ourselves.

So the question is, if I need a lot of objects, don’t I have to create them one by one, and if the object I need also depends on other objects, in order to create the object I need, I have to instantiate the object that the object depends on.

Suppose object A depends on B, C, and D, and B depends on E.

As shown in the figure:

Express this relationship in code:

Public constructor(E) {public constructor(E); Class C E) {}} {} {} {} class E class D / / A relies on B, C, D class A {public constructor (public B: B, C: public C, public d: D) { } }Copy the code

Create an instance of A:

var e = new E();
var b = new B(e);
var c = new C();
var d = new D();
var a = new A(b,c,d);
Copy the code

As you can see, to create an instance of class A, we need to create instances of B, C, and D, and to create an instance of B, we need to create an instance of E.

In this process, the programmer needs to actively trace all the dependencies of a class and build the relationship himself. This is undoubtedly a very heavy work, especially when the dependency tree becomes large, tracing the dependencies can become tricky, even difficult to accomplish.

At this point, a natural thought occurred to me: is there a tool that just tells it what class of object it needs, and it can automatically find dependencies for me and automatically create that object?

The answer is yes, the well-known Ioc container, known in Angular as dependency injection.

Inversion of control containers, as the name suggests, are objects that used to actively build dependencies, but now we hand over the control of creating dependencies to the container without doing the dirty work.

Implementing dependency injection

Implementing a dependency injection is as simple as getting the type of the parameter, recursively looking for the dependency and instantiating the injection.

// filename: ioc.ts // Import metadata support "reflect-metadata"; // Store all classes that can be used as dependencies const classPool: Array<Function> = []; Export function Injectable (_constructor: function) {// Use reflection to get a list of parameter types. Array<Function> = Reflect.getMetadata('design:paramtypes', _constructor); if (classPool.indexOf(_constructor) ! == -1) { return; } else if (paramsTypes. Length) {paramsTypes. ForEach ((v, I) => {if (v === _constructor) {throw new Error(' not dependent on itself '); } else if (classpool.indexof (v) === -1) {throw new Error(' dependent on ${I}[${(v as any).name}] cannot be injected '); }}); } classPool.push(_constructor); Export function create<T>(_constructor: {new (... Args: Array<any>): T}): T {let paramsTypes: Array<Function> = Reflect.getMetadata('design:paramtypes', _constructor); // Let paramInstances = paramstypes.map ((v, I) = > {/ / parameter is injected into the if (classPool. IndexOf (v) = = = 1) {throw new Error (` parameters ${I} [${as any (v). The name}] shall not be injected `); } else if (v.length) {return create(v as any); } else {return new (v as any)(); }}); return new _constructor(... paramInstances); }Copy the code

It’s much easier to go back to the above example of creating an A object with dependency injection:

import { injectable , create } from 'ioc'; @injectable class B { public constructor(public a: E) { } } @injectable class C { } @injectable class D { } @injectable class E { } @injectable class A { public Constructor (public b: b, public C: c, public d: d) {}} let a = create(a); Var e = new e (); var e = new e (); //var b = new B(e); //var c = new C(); //var d = new D(); //var a = new A(b,c,d);Copy the code