Reputation: 182
As documentation says
Dependency Injection is a powerful pattern for managing code dependencies
But does Angular's DI has any sense?
Let's say we have an HeroComponent living in the HeroModule, and it uses HeroService. To use it in HeroComponent we have to:
Why don't just
We can export its instance so we can still have a singleton across our app and we can configure our webpack/karma to be still able to import mocks instead of real implementations inside our tests.
Someone can say Angular's DI makes architecture less tightly coupled, but is it true? In Angular 1.x indeed you just specified params in the constructor. But in Angular2 you have to import your dependency additionally, and you have to specify from where. So where is this loosely coupling?
Example:
import { Http } from 'angular2/http';
export class Login {
constructor(http: Http) {
http.whatever()
}
}
To be able to execute our injection, we have to import it. And when we import, we define exactly what service we are going to use. I don't see any difference from above and below example:
import { http } from 'angular2/http'; (instance)
export class Login {
constructor() {
http.whatever()
}}
Upvotes: 1
Views: 324
Reputation: 12378
Dependency injection is not about importing. It's about having the instances created for you outside of your components. Without DI your HeroComponent
would still need to add the import statement for the HeroService
and you'd need to manually instantiate it inside HeroComponent
:
myHeroService: HeroService = new HeroService();
Now imagine you need to use this service in three components. Then you'll need to write the above line in three different places.
What if you need to use a mock service because the real one is not ready yet (or you want to have a mock service for unit tests)? Without DI you'd need to modify the code in three components to something like this:
myHeroService: MockHeroService = new MockHeroService();
With DI each of the three components would have the same constructors that you'd never modify in the above scenario, e.g.:
class HeroComponent{
constructor(heroService: HeroService){}
}
Switching to the MockHeroService
would require only one change (the provider) in the HeroModule
declaration:
@NgModule({
...
providers:[provide: HeroService, useClass: MockHeroService]
})
The above code would instruct Angular to create a singleton for the entire module (app). If you decide to introduce more than one instance of HeroService
(say HeroComponent1
uses HeroService
, and HeroComponent2
uses MockHeroService
), then just declare providers:[HeroService]
in the HeroComponent1
:
@Component({
...
providers:[HeroService]
})
Now Angular will create a MockHeroService
instance for the entire app and another instance of the HeroService
for the HeroComponent1
and its children.
Keep in mind that you wouldn't need to change the constructors' signatures in any components that use this service.
Now imagine that you'd decide that in one component you want to introduce a factory function that would conditionally instantiate either HeroService
or MockHeroService
. You'd just declare a provider for such component using the useFactory
syntax.
I can keep going :)
Upvotes: 1