What is DI?
So dependency injection makes programmers' lives easier, but what does itreally do?
Consider the following code:
class Hamburger {
private bun: Bun;
private patty: Patty;
private toppings: Toppings;
constructor() {
this.bun = new Bun('withSesameSeeds');
this.patty = new Patty('beef');
this.toppings = new Toppings(['lettuce', 'pickle', 'tomato']);
}
}
The above code is a contrived class that represents a hamburger. The classassumes a Hamburger
consists of a Bun
, Patty
and Toppings
. The classis also responsible for making the Bun
, Patty
and Toppings
. This is abad thing. What if a vegetarian burger were needed? One naive approach mightbe:
class VeggieHamburger {
private bun: Bun;
private patty: Patty;
private toppings: Toppings;
constructor() {
this.bun = new Bun('withSesameSeeds');
this.patty = new Patty('tofu');
this.toppings = new Toppings(['lettuce', 'pickle', 'tomato']);
}
}
There, problem solved right? But what if we need a gluten free hamburger?What if we want different toppings… maybe something more generic like:
class Hamburger {
private bun: Bun;
private patty: Patty;
private toppings: Toppings;
constructor(bunType: string, pattyType: string, toppings: string[]) {
this.bun = new Bun(bunType);
this.patty = new Patty(pattyType);
this.toppings = new Toppings(toppings);
}
}
Okay this is a little different, and it's more flexible in some ways, but it isstill quite brittle. What would happen if the Patty
constructor changed toallow for new features? The whole Hamburger
class would have to be updated.In fact, any time any of these constructors used in Hamburger
's constructorare changed, Hamburger
would also have to be changed.
Also, what happens during testing? How can Bun
, Patty
and Toppings
beeffectively mocked?
Taking those concerns into consideration, the class could be rewritten as:
class Hamburger {
private bun: Bun;
private patty: Patty;
private toppings: Toppings;
constructor(bun: Bun, patty: Patty, toppings: Toppings) {
this.bun = bun;
this.patty = patty;
this.toppings = toppings;
}
}
Now when Hamburger
is instantiated it does not need to know anything about itsBun
, Patty
, or Toppings
. The construction of these elements has beenmoved out of the class. This pattern is so common that TypeScript allows it tobe written in shorthand like so:
class Hamburger {
constructor(private bun: Bun, private patty: Patty,
private toppings: Toppings) {}
}
The Hamburger
class is now simpler and easier to test. This model of havingthe dependencies provided to Hamburger
is basic dependency injection.
However there is still a problem. How can the instantiation of Bun
,Patty
and Toppings
best be managed?
This is where dependency injection as a framework can benefit programmers, andit is what Angular provides with its dependency injection system.
原文: https://angular-2-training-book.rangle.io/handout/di/what_is_di.html