翻译完了多级注入器
This commit is contained in:
parent
0b2ff0ee28
commit
22359a2496
|
@ -97,14 +97,23 @@ figure.image-display
|
|||
|
||||
:marked
|
||||
### Re-providing a service at different levels
|
||||
|
||||
### 在不同层级再次提供同一个服务
|
||||
|
||||
You can re-register a provider for a particular dependency token at multiple levels of the injector tree.
|
||||
You don't *have* to re-register providers. You shouldn't do so unless you have a good reason.
|
||||
But you *can*.
|
||||
|
||||
我们可以在注入器树中的多个层次上为指定的依赖令牌重新注册提供商。
|
||||
但*并非必须*重新注册,事实上,虽然可以重新注册,但除非有很好的理由,否则不应该这么做。
|
||||
|
||||
As the resolution logic works upwards, the first provider encountered wins.
|
||||
Thus, a provider in an intermediate injector intercepts a request for a service from something lower in the tree.
|
||||
It effectively "reconfigures" and "shadows" a provider at a higher level in the tree.
|
||||
|
||||
服务解析逻辑会自下而上查找,碰到的第一个提供商会胜出。
|
||||
因此,注入器树中间层注入器上的提供商,可以拦截来自底层的对特定服务的请求。
|
||||
这导致它可以"重新配置"和者说"遮蔽"高层的注入器。
|
||||
|
||||
If you only specify providers at the top level (typically the root `AppModule`), the tree of injectors appears to be flat.
|
||||
All requests bubble up to the root <code>NgModule</code> injector that you configured with the `bootstrapModule` method.
|
||||
|
@ -123,19 +132,32 @@ figure.image-display
|
|||
在不同层次上重新配置一个或多个提供商的能力,开启了一些既有趣又有用的可能性。
|
||||
|
||||
### Scenario: service isolation
|
||||
|
||||
### 场景:服务隔离
|
||||
|
||||
Architectural reasons may lead you to restrict access to a service to the application domain where it belongs.
|
||||
|
||||
出于架构方面的考虑,可能会让你决定把一个服务限制到只能在它所属的特定领域中访问。
|
||||
|
||||
The guide sample includes a `VillainsListComponent` that displays a list of villains.
|
||||
It gets those villains from a `VillainsService`.
|
||||
|
||||
本章的范例中包括一个`VillainsListComponent`,它显示一个反派的列表。
|
||||
|
||||
While you _could_ provide `VillainsService` in the root `AppModule` (that's where you'll find the `HeroesService`),
|
||||
that would make the `VillainsService` available everywhere in the application, including the _Hero_ workflows.
|
||||
|
||||
虽然我们也可以在根模块`AppModule`中提供`VillainsService`(就像`HeroesService`那样),不过那样一来就会导致在整个应用中到处都能访问到`VillainsService`,包括在*英雄*工作流中。
|
||||
|
||||
If you later modified the `VillainsService`, you could break something in a hero component somewhere.
|
||||
That's not supposed to happen but providing the service in the root `AppModule` creates that risk.
|
||||
|
||||
如果我们以后修改了`VillainsService`,那就可能会破坏英雄组件中的某些部分。
|
||||
这可不妙,但是在根模块`AppModule`中提供这个服务可能会导致这种风险。
|
||||
|
||||
Instead, provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
|
||||
|
||||
我们可以换一种方案:在`VillainsListComponent`元数据的`providers`中提供`VillainsService`,就像这样:
|
||||
|
||||
+makeExcerpt('src/app/villains-list.component.ts (metadata)')
|
||||
|
||||
|
@ -143,26 +165,52 @@ figure.image-display
|
|||
By providing `VillainsService` in the `VillainsListComponent` metadata and nowhere else,
|
||||
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
|
||||
It's still a singleton, but it's a singleton that exist solely in the _villain_ domain.
|
||||
|
||||
在`VillainsListComponent`的元数据中而不是其它地方提供`VillainsService`服务,该服务就会只在`VillainsListComponent`及其子组件树中可用。
|
||||
它仍然是单例,但是这个单例只存在于*反派(villain)*这个领域中。
|
||||
|
||||
Now you know that a hero component can't access it. You've reduced your exposure to error.
|
||||
|
||||
现在,我们可以确信英雄组件不会访问它,因此减少了犯错误的机会。
|
||||
|
||||
### Scenario: multiple edit sessions
|
||||
|
||||
### 场景:多重编辑会话
|
||||
|
||||
Many applications allow users to work on several open tasks at the same time.
|
||||
For example, in a tax preparation application, the preparer could be working on several tax returns,
|
||||
switching from one to the other throughout the day.
|
||||
|
||||
很多应用允许用户同时进行多个任务。
|
||||
比如,在纳税申报应用中,申报人可以打开多个报税单,随时可能从一个切换到另一个。
|
||||
|
||||
This guide demonstrates that scenario with an example in the Tour of Heroes theme.
|
||||
Imagine an outer `HeroListComponent` that displays a list of super heroes.
|
||||
|
||||
本章要示范的场景仍然是基于《英雄指南》的。
|
||||
想象一个外层的`HeroListComponent`,它显示一个超级英雄的列表。
|
||||
|
||||
To open a hero's tax return, the preparer clicks on a hero name, which opens a component for editing that return.
|
||||
Each selected hero tax return opens in its own component and multiple returns can be open at the same time.
|
||||
|
||||
要打开一个英雄的报税单,申报者点击英雄名,它就会打开一个组件来编辑那个申报单。
|
||||
每个选中的申报单都会在自己的组件中打开,并且可以同时打开多个申报单。
|
||||
|
||||
Each tax return component has the following characteristics:
|
||||
|
||||
每个报税单组件都有下列特征:
|
||||
|
||||
* Is its own tax return editing session.
|
||||
|
||||
属于它自己的报税单会话。
|
||||
|
||||
* Can change a tax return without affecting a return in another component.
|
||||
|
||||
可以修改一个报税单,而不会影响另一个组件中的申报单。
|
||||
|
||||
* Has the ability to save the changes to its tax return or cancel them.
|
||||
|
||||
能把所做的修改保存到它的报税单中,或者放弃它们。
|
||||
|
||||
figure.image-display
|
||||
img(src="/resources/images/devguide/dependency-injection/hid-heroes-anim.gif" width="400" alt="Heroes in action")
|
||||
|
@ -172,15 +220,26 @@ figure.image-display
|
|||
That would be a pretty easy task for a simple hero tax return.
|
||||
In the real world, with a rich tax return data model, the change management would be tricky.
|
||||
You might delegate that management to a helper service, as this example does.
|
||||
|
||||
实现方式之一就是让`HeroTaxReturnComponent`有逻辑来管理和还原那些更改。
|
||||
这对于简单的报税单来说是很容易的。
|
||||
不过,在现实世界中,报税单的数据模型非常复杂,对这些修改的管理可能不得不投机取巧。
|
||||
于是我们可以把这种管理任务委托给一个辅助服务,就像这个例子中所做的。
|
||||
|
||||
Here is the `HeroTaxReturnService`.
|
||||
It caches a single `HeroTaxReturn`, tracks changes to that return, and can save or restore it.
|
||||
It also delegates to the application-wide singleton `HeroService`, which it gets by injection.
|
||||
|
||||
这是一个报税单服务`HeroTaxReturnService`。
|
||||
它缓存了单条`HeroTaxReturn`,用于跟踪那个申报单的变更,并且可以保存或还原它。
|
||||
它还委托给了全应用级的单例服务`HeroService`,它是通过依赖注入机制取得的。
|
||||
|
||||
+makeExample('src/app/hero-tax-return.service.ts')
|
||||
|
||||
:marked
|
||||
Here is the `HeroTaxReturnComponent` that makes use of it.
|
||||
|
||||
下面是正在使用它的`HeroTaxReturnComponent`组件。
|
||||
|
||||
+makeExample('src/app/hero-tax-return.component.ts')
|
||||
|
||||
|
@ -189,13 +248,22 @@ figure.image-display
|
|||
The setter initializes the component's own instance of the `HeroTaxReturnService` with the incoming return.
|
||||
The getter always returns what that service says is the current state of the hero.
|
||||
The component also asks the service to save and restore this tax return.
|
||||
|
||||
我们通过输入属性得到*要编辑的报税单*,我们把它实现成了读取器(getter)和设置器(setter)。
|
||||
设置器根据传进来的报税单初始化了组件自己的`HeroTaxReturnService`实例。
|
||||
读取器总是返回该服务所存英雄的当前状态。
|
||||
组件也会请求该服务来保存或还原这个报税单。
|
||||
|
||||
There'd be big trouble if _this_ service were an application-wide singleton.
|
||||
Every component would share the same service instance.
|
||||
Each component would overwrite the tax return that belonged to another hero.
|
||||
What a mess!
|
||||
|
||||
这里有个大问题,那就是如果*这个*服务是一个全应用范围的单例,每个组件就都会共享同一个服务实例,每个组件也都会覆盖属于其他英雄的报税单,真是一团糟!
|
||||
|
||||
Look closely at the metadata for the `HeroTaxReturnComponent`. Notice the `providers` property.
|
||||
|
||||
但仔细看`HeroTaxReturnComponent`的元数据,注意`providers`属性。
|
||||
|
||||
+makeExcerpt('src/app/hero-tax-return.component.ts', 'providers', '')
|
||||
|
||||
|
@ -204,38 +272,63 @@ figure.image-display
|
|||
Recall that every component _instance_ has its own injector.
|
||||
Providing the service at the component level ensures that _every_ instance of the component gets its own, private instance of the service.
|
||||
No tax return overwriting. No mess.
|
||||
|
||||
`HeroTaxReturnComponent`有它自己的`HeroTaxReturnService`提供商。
|
||||
回忆一下,每个组件的*实例*都有它自己的注入器。
|
||||
在组件级提供服务可以确保组件的*每个*实例都得到一个自己的、私有的服务实例。
|
||||
报税单不会再被意外覆盖,这下清楚了。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation.
|
||||
You can review it and download it from the <live-example></live-example>.
|
||||
|
||||
该场景代码中的其它部分依赖另一些Angular的特性和技术,我们将会在本文档的其它章节学到。
|
||||
你可以到<live-example></live-example>查看代码和下载它。
|
||||
|
||||
:marked
|
||||
### Scenario: specialized providers
|
||||
|
||||
### 场景:专门的提供商
|
||||
|
||||
Another reason to re-provide a service is to substitute a _more specialized_ implementation of that service,
|
||||
deeper in the component tree.
|
||||
|
||||
重新提供服务的另一个原因,是在组件树的深层中把该服务替换为一个*更特殊的*实现。
|
||||
|
||||
Consider again the Car example from the [Dependency Injection](./dependency-injection.html) guide.
|
||||
Suppose you configured the root injector (marked as A) with _generic_ providers for
|
||||
`CarService`, `EngineService` and `TiresService`.
|
||||
|
||||
再次考虑[依赖注入](./dependency-injection.html)一章中车辆(Car)的例子。
|
||||
假设我们在根注入器(代号A)中配置了*通用的*提供商:`CarService`、`EngineService`和`TiresService`。
|
||||
|
||||
You create a car component (A) that displays a car constructed from these three generic services.
|
||||
|
||||
我们创建了一个车辆组件(A),它显示一个从另外三个通用服务构造出的车辆。
|
||||
|
||||
Then you create a child component (B) that defines its own, _specialized_ providers for `CarService` and `EngineService`
|
||||
that have special capabilites suitable for whatever is going on in component (B).
|
||||
|
||||
然后,我们创建一个子组件(B),它为`CarService`和`EngineService`定义了自己的*特殊的*提供商,它们具有更特殊的能力,适用于组件B的。
|
||||
|
||||
Component (B) is the parent of another component (C) that defines its own, even _more specialized_ provider for `CarService`.
|
||||
|
||||
组件B是另一个组件C的父组件,而组件C又定义了自己的,*更特殊的*`CarService`提供商。
|
||||
|
||||
figure.image-display
|
||||
img(src="/resources/images/devguide/dependency-injection/car-components.png" alt="car components" width="220")
|
||||
|
||||
:marked
|
||||
Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
|
||||
|
||||
在幕后,每个组件都有自己的注入器,这个注入器带有为组件本身准备的0个、1个或多个提供商。
|
||||
|
||||
When you resolve an instance of `Car` at the deepest component (C),
|
||||
its injector produces an instance of `Car` resolved by injector (C) with an `Engine` resolved by injector (B) and
|
||||
`Tires` resolved by the root injector (A).
|
||||
|
||||
当我们在最深层的组件C解析`Car`的实例时,它使用注入器C解析生成了一个`Car`的实例,使用注入器B解析了`Engine`,而`Tires`则是由根注入器A解析的。
|
||||
|
||||
figure.image-display
|
||||
img(src="/resources/images/devguide/dependency-injection/injector-tree.png" alt="car injector tree" width="600")
|
||||
|
@ -244,6 +337,9 @@ figure.image-display
|
|||
:marked
|
||||
The code for this _cars_ scenario is in the `car.components.ts` and `car.services.ts` files of the sample
|
||||
which you can review and download from the <live-example></live-example>.
|
||||
|
||||
*车辆*场景下的代码位于`car.components.ts`和`car.services.ts`文件中,这个例子你可以在<live-example></live-example>查看和下载。
|
||||
|
||||
//- ## Advanced Dependency Injection in Angular
|
||||
//- Restrict Dependency Lookups
|
||||
//- [TODO] (@Host) This has been postponed for now until we come up with a decent use case
|
||||
|
|
Loading…
Reference in New Issue