为什么 DI 在 Angular 中的 class 构造函数中完成?
Why DI is done at class Constructor in Angular?
我一直在浏览这篇关于 Angular 服务的文章。并且想知道为什么通常只在 class 构造函数中创建服务实例?
例如:- 某些 DemoService class 需要在某些 DemoComponent 中使用。服务的实例通常会在 class 构造函数中创建。
@Injectable()
export class DemoService {
...
}
演示组件
@Component({
selector: 'app-demo',
templateUrl: './demo.component.html',
})
export class DemoComponent implements OnInit {
...
constructor(
private demoService: DemoService
) {}
...
}
所以,我的 问题 是,我们是否也可以在 ngOnInit()
生命周期挂钩方法中实例化服务?
做类似 - 或者其他地方的事情。
ngOnInit() {
// using new DemoService();
}
谢谢。
一般来说,ngOnInit()
不会发生这种情况。 Angular的DI机制需要在bootstrap时构建注入依赖的依赖树。它需要知道
- 它必须创建的所有对象和
- 它必须按什么顺序创建对象,
- 它正在创建的依赖项的所有注入点。
当我们使用Angular的DI时,我们让Angular为我们实例化和管理对象。我们不自己做。这样做的好处是使代码非常易于测试,还有其他好处。
DI 和对象实例化发生在构造函数中,因为这是创建实际对象和对象依赖项的时间。
在ngOnInit()
中,依赖树中的所有对象都已经构建,所以此时进行依赖注入为时已晚。
但是,可以要求 Angular 的 注入器给我们一个它正在管理的对象(但再次 Angular 已经实例化了对象, 不是我们)。在某些通常很少见的情况下,可能需要使用注入器来获取对象实例。但通常,最好让这一切都在 Angular 的对象树构造 bootstrap 阶段处理。
我在这里想到 DI 的一个很好的原因是服务的 constructor
参数(服务的 DI)。
当您使用 DI
在组件中注入服务时,您不再担心服务 constructor
参数(如果有的话)。 Angular自己处理。
例如:
服务
@Injectable()
export class DemoService {
constructor(myService : MyService){}
}
所以当你有像上面这样的服务时,如果你没有使用DI
,那么你关心这里的myService
参数。
为了前任你会做
组件
constructor(){
let myService = new MyService();
this.demoService = new DemoService(myService)
}
自己写服务也行。
如果您从某个图书馆使用它怎么办?你不知道要传递什么参数
Dependency Injection 是一种在许多编程语言中使用的软件设计模式。以下是维基百科对此的描述:
In software engineering, dependency injection is a technique whereby one object (or static method) supplies the dependencies of another object. A dependency is an object that can be used (a service). Injection is the passing of dependency to a dependent object (a client) that would use it. Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.
以下是 class 自行创建依赖实例的问题以及 Angular 的 DI 如何解决它:
- 难以维护。如果依赖项的构造函数发生更改,那么我们必须将更改传播到代码中实例化 class 的所有位置。
考虑这段代码,来自 DEPENDENCY INJECTION IN ANGULAR - Thoughtram,例如:
class Car {
constructor() {
this.engine = new Engine();
this.tires = Tires.getInstance();
this.doors = app.get('doors');
}
}
此处,由于 Car class 正在自行创建其依赖项的实例,如果明天,比方说,Engine
class 的构造函数已更新为需要一个fuelType
,我们必须将其传递给 Engine
构造函数,否则我们的代码将无法运行。每次创建依赖项的方式发生变化时,我们都必须在创建该依赖项实例的每个地方进行更改。
解决方案: 如果我们依靠 Angular 的注入器为我们提供这些依赖项,这看起来像这样:
class Car {
constructor(engine, tires, doors) {
this.engine = engine;
this.tires = tires;
this.doors = doors;
}
}
如您所见,Car
class 无需担心更改其中的任何内容,因为它不必担心创建其依赖项的实例。
Just imagine you’d like to test this class. How would you replace Engine with a MockEngine dependency in that code? When writing tests, we want to test different scenarios that our code is used in, hence each scenario needs its own configuration. If we want to write testable code, we need to write reusable code. Our code should work in any environment as long as all dependencies are satisfied. Which brings us to the conclusion that testable code is reusable code and vise versa.
解决方案: 如果我们使用 Angular 的 DI,代码将如下所示:
var car = new Car(
new MockEngine(),
new MockTires(),
new MockDoors()
);
看,为我们的任何依赖项创建 Mock 是多么容易。
- 不是单例。创建的所有依赖项对于 class 都是本地的。因此,如果您愿意,您将无法在多个 class 之间共享单个服务。数据共享将难以管理,并且会使整个设置变得越来越复杂。观看 "Why Dependency Injection" by kudvenkat 了解更多。
解决方案: 如果我们依赖 Angular 的注入器来处理这些依赖项,我们可以确定 Angular 的注入器将除非另有说明(如果您向组件的 providers
添加服务)
,请向我们提供单例
我又来了,在 Angular:
中链接了一些对您理解 DI 非常有帮助的资源
我一直在浏览这篇关于 Angular 服务的文章。并且想知道为什么通常只在 class 构造函数中创建服务实例?
例如:- 某些 DemoService class 需要在某些 DemoComponent 中使用。服务的实例通常会在 class 构造函数中创建。
@Injectable()
export class DemoService {
...
}
演示组件
@Component({
selector: 'app-demo',
templateUrl: './demo.component.html',
})
export class DemoComponent implements OnInit {
...
constructor(
private demoService: DemoService
) {}
...
}
所以,我的 问题 是,我们是否也可以在 ngOnInit()
生命周期挂钩方法中实例化服务?
做类似 - 或者其他地方的事情。
ngOnInit() {
// using new DemoService();
}
谢谢。
一般来说,ngOnInit()
不会发生这种情况。 Angular的DI机制需要在bootstrap时构建注入依赖的依赖树。它需要知道
- 它必须创建的所有对象和
- 它必须按什么顺序创建对象,
- 它正在创建的依赖项的所有注入点。
当我们使用Angular的DI时,我们让Angular为我们实例化和管理对象。我们不自己做。这样做的好处是使代码非常易于测试,还有其他好处。
DI 和对象实例化发生在构造函数中,因为这是创建实际对象和对象依赖项的时间。
在ngOnInit()
中,依赖树中的所有对象都已经构建,所以此时进行依赖注入为时已晚。
但是,可以要求 Angular 的 注入器给我们一个它正在管理的对象(但再次 Angular 已经实例化了对象, 不是我们)。在某些通常很少见的情况下,可能需要使用注入器来获取对象实例。但通常,最好让这一切都在 Angular 的对象树构造 bootstrap 阶段处理。
我在这里想到 DI 的一个很好的原因是服务的 constructor
参数(服务的 DI)。
当您使用 DI
在组件中注入服务时,您不再担心服务 constructor
参数(如果有的话)。 Angular自己处理。
例如:
服务
@Injectable()
export class DemoService {
constructor(myService : MyService){}
}
所以当你有像上面这样的服务时,如果你没有使用DI
,那么你关心这里的myService
参数。
为了前任你会做
组件
constructor(){
let myService = new MyService();
this.demoService = new DemoService(myService)
}
自己写服务也行。
如果您从某个图书馆使用它怎么办?你不知道要传递什么参数
Dependency Injection 是一种在许多编程语言中使用的软件设计模式。以下是维基百科对此的描述:
In software engineering, dependency injection is a technique whereby one object (or static method) supplies the dependencies of another object. A dependency is an object that can be used (a service). Injection is the passing of dependency to a dependent object (a client) that would use it. Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.
以下是 class 自行创建依赖实例的问题以及 Angular 的 DI 如何解决它:
- 难以维护。如果依赖项的构造函数发生更改,那么我们必须将更改传播到代码中实例化 class 的所有位置。
考虑这段代码,来自 DEPENDENCY INJECTION IN ANGULAR - Thoughtram,例如:
class Car {
constructor() {
this.engine = new Engine();
this.tires = Tires.getInstance();
this.doors = app.get('doors');
}
}
此处,由于 Car class 正在自行创建其依赖项的实例,如果明天,比方说,Engine
class 的构造函数已更新为需要一个fuelType
,我们必须将其传递给 Engine
构造函数,否则我们的代码将无法运行。每次创建依赖项的方式发生变化时,我们都必须在创建该依赖项实例的每个地方进行更改。
解决方案: 如果我们依靠 Angular 的注入器为我们提供这些依赖项,这看起来像这样:
class Car {
constructor(engine, tires, doors) {
this.engine = engine;
this.tires = tires;
this.doors = doors;
}
}
如您所见,Car
class 无需担心更改其中的任何内容,因为它不必担心创建其依赖项的实例。
Just imagine you’d like to test this class. How would you replace Engine with a MockEngine dependency in that code? When writing tests, we want to test different scenarios that our code is used in, hence each scenario needs its own configuration. If we want to write testable code, we need to write reusable code. Our code should work in any environment as long as all dependencies are satisfied. Which brings us to the conclusion that testable code is reusable code and vise versa.
解决方案: 如果我们使用 Angular 的 DI,代码将如下所示:
var car = new Car(
new MockEngine(),
new MockTires(),
new MockDoors()
);
看,为我们的任何依赖项创建 Mock 是多么容易。
- 不是单例。创建的所有依赖项对于 class 都是本地的。因此,如果您愿意,您将无法在多个 class 之间共享单个服务。数据共享将难以管理,并且会使整个设置变得越来越复杂。观看 "Why Dependency Injection" by kudvenkat 了解更多。
解决方案: 如果我们依赖 Angular 的注入器来处理这些依赖项,我们可以确定 Angular 的注入器将除非另有说明(如果您向组件的 providers
添加服务)
我又来了,在 Angular:
中链接了一些对您理解 DI 非常有帮助的资源