1

我有一个在两种不同模式下工作的应用程序:演示和正常。演示模式仅在用户没有帐户并且只想尝试应用程序以查看其工作原理时使用。

现在假设我们有一个在应用程序中使用的服务。例如检索Account和验证用户的服务:

abstract class AccountService {
  authenticate(username: string, password: string): Observable<Boolean>;
  getAccount(): Observable<Account>;
}

对于这个服务,我们有两种实现,每种模式一个。AccountServiceImpl,对于普通模式,向某个服务器执行 HTTP 请求以检索帐户。而AccountServiceDemoImpl只是返回一个硬编码的。

假设我们有一个AccountComponent向用户显示帐户名称的组件。对于这个组件,我们使用哪个实现并不重要,所以我们只需AccountService在它的构造函数中注入一个。

一切都很好,我们可以轻松地使用任一实现来填写 AccountComponent。现在,当用户单击登录页面上的按钮时,我们希望能够在运行时在这些实现之间切换。所以我写了一个工厂提供者来确定使用哪个 AccountService 实现

{provide: AccountService, deps[AccountServiceImpl, AccountServiceDemoImpl], (regularService, demoService) => demoModeActivated ? demoService : regularService}

可以想象,AccountService在登录页面上也注入了 来处理用户的认证。这意味着该工厂已经过评估。现在,问题是这个评估的结果被缓存在 Angular 中。因此,当激活演示模式并且用户导航到 时AccountComponent,实际AccountServiceImpl将再次注入。

有没有办法清除 DI 缓存(对于一组特定的 DI 令牌)?还是我应该尝试以其他方式处理此功能?(例如,编写AccountService委托给AccountServiceImpl或 的另一个实现AccountServiceDemoImpl。)

4

1 回答 1

2

最初,工厂供应商似乎会为您解决这个问题。不幸的是,工厂左轮手枪是同步的,您依靠异步调用来确定要提供的服务。

相反,您可以使用 Resolve 守卫。在 resolve 方法中,您将返回一个调用 auth 方法的可观察对象,然后映射到更新任一服务。然后调用 first() 操作符在第一次执行后完成 observable。

它解决了警卫似乎被设计为返回简单的 DTO 结构,而不是服务。但这有效。

您可以在 Resolve Guard 中注入这两个服务并映射到其中一个,而不是新建实例,以防您希望此服务保持为单例。

export class AccountServiceResolver implements Resolve<AccountService> {

  constructor(private accountService: AccountService, demmoService: AccountDemoService) { }

  resolve(): Observable<AccountService> {

    return this.accountService.getAccount().map(account => {

      if (account.real) {
        return this.accountService;
      } else {
        return this.demoService;
      }
    }).first();
  }

}

然后在你的组件中得到这个:

ngOnInit(route: ActivatedRoute) {

  const service = route.data[0];
}
于 2017-05-25T08:47:13.813 回答