Angular 依赖注入框架里 useExisting 和 useClass 的使用场景

发布于:2022-11-28 ⋅ 阅读:(393) ⋅ 点赞:(0)

StackOverflow上的一个帖子.

从上图能看出,所有注入的示例都通过factory方法返回,只是factory方法的实现有所差异。

As we can see in the picture above all of providers can be presented similar useFactory. When it’s the time to get an instance of provider angular just calls factory function.

一些例子:

{provide: Class1, useClass: Class1}

等价于:

Class1

而:

{provide: Class1, useClass: Class3}

you can configure, that when a constructor requests Class1 Angular DI creates an instance of Class3 and passes it to the constructor.

当构造函数的参数需要传入Class1时,Angular DI传入一个Class3的框实例到构造函数里。

而下面这个例子:

{provide: Class2, useExisting: Class2}

doesn’t result in an instance being created, but you can see this rather than an alias. If a constructor requests Class2, Angular DI looks for another provider for key Class2 and injects the instance from this Class2 provider. You can see useExisting like a reference to another provider or an alias.

当构造函数需要Class2时,Angular DI从另一个key为Class2的provider里查找,取出对应的实例进行注入。

Injectable and Provider are 2 different things. The injectable is a class DI can create an instance of, or a provided value that might be passed to a constructor. A provider is an entry in a registry of providers that DI maintains and that allows to lookup up providers by key (key is the type of a constructor parameter, a string or an InjectToken). The provider also holds information about how to “create” the injectable value/instance. DI looks up a provider, the provider provides the value, and DI passes the value (instance of an injectable or a value provided as-is) to a constructor.

Injectable和Provider是两个不同的概念。Injectable是一个class,Angular DI可以基于该class创建实例,或者DI可以提供一个值,能够传递到constructor里。DI内部维护了一个provider注册表,该注册表支持根据key查询provider.

Key is the type of a constructor parameter, a string or an InjectToken)

key是构造函数的参数,一个字符串或者InjectToken. Provider有足够的knowledge知道如何去创建一个value或者实例。

DI询问provider,provider提供值,DI将值传递到构造函数里。

If you register MyClass as provider, this is the short form of { provide: MyClass, useClass: MyValue } where provide: MyClass is the key a provider can be found with, and useClass: MyValue is a strategy passed to the provider that informs the provider what value it should provide for this key.

provide: MyClass是provider的key,Angular DI注册表里根据这个key找到provider.

useClass: MyValue, 一个传递给provider的strategy,告诉provider对于指定的key,应该提供何种value.

  • useClass: MyValue相当于"use new MyClass(…)"

  • useExisting: Foo

DI需要去查找key为Foo的provider,然后注入Foo provider提供的value.

看一些具体的例子。

UseExisting

在注入ServiceOldS时,使用ServiceNewS这个provider提供的值。

因此,运行时,old和newService两个实例指向的都是newService实例,都是ServiceNewS这个provider注入的实例:

所以最后UI上显示:

useClass

ServiceOldS被注入的是new ServiceNewS,

且和newService的实例不同,所以最后显示new service.

[{ provide: Logger, useClass: Logger }]

  • The provide property holds the token that serves as the key for both locating a dependency value and configuring the injector.

别名提供者:useExisting

useExisting 提供了一个键,让你可以把一个令牌映射成另一个令牌。实际上,第一个令牌就是第二个令牌所关联的服务的别名,这样就创建了访问同一个服务对象的两种途径。

{ provide: MinimalLogger, useExisting: LoggerService }

useExisting 的作用

你可以使用别名接口来窄化 API。下面的例子中使用别名就是为了这个目的。

想象 LoggerService 有个很大的 API 接口,远超过现有的三个方法和一个属性。你可能希望把 API 接口收窄到只有两个你确实需要的成员。在这个例子中,MinimalLogger类-接口,就这个 API 成功缩小到了只有两个成员:

// Class used as a "narrowing" interface that exposes a minimal logger
// Other members of the actual implementation are invisible
export abstract class MinimalLogger {
  abstract logs: string[];
  abstract logInfo: (msg: string) => void;
}

消费代码:

@Component({
  selector: 'app-hero-of-the-month',
  templateUrl: './hero-of-the-month.component.html',
  // TODO: move this aliasing, `useExisting` provider to the AppModule
  providers: [{ provide: MinimalLogger, useExisting: LoggerService }]
})
export class HeroOfTheMonthComponent {
  logs: string[] = [];
  constructor(logger: MinimalLogger) {
    logger.logInfo('starting up');
  }
}

HeroOfTheMonthComponent 构造函数的 logger 参数是一个 MinimalLogger 类型,在支持 TypeScript 感知的编辑器里,只能看到它的两个成员 logs 和 logInfo:

在这里插入图片描述

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到