避免循环依赖注入

Avoid Circular Dependency injection

在我的 Angular 应用程序中,我正在实施 2 项服务:

这两个服务相互依赖:

  1. 当我注销时,我必须停止监视用户闲置(通过调用 IdleService 中的方法)
  2. 当用户超时时,我必须从 AuthenticationService 调用 logout 方法来注销用户。

这种方法会导致循环依赖问题。您知道如何避免它或如何通过更好的方法改变我的实际方法吗?

您可以在 IdleService 中创建一个 observable 或一个主题,如果时间用完,returns 一个断开消息。这样,只有 AuthenticationService 导入 IdleService。例如:

import { IdleService } from './services/idle.service';
import { Observable } from 'rxjs/Observable'; 

@Injectable()
export class AuthenticationService {

  disconnect: Obervable<boolean>;

  constructor(private idleService: IdleService) { 
    this.disconnect = this.idleService.disconnectObservable;
    this.disconnect.subscribe(res => {
      if (res === true) {
        this.logout();
      }
    });
  }

  logout() {
  //some code here
  }
}

IdleService中:

import { Observable } from 'rxjs/Observable';

@Injectable()
export class IdleService {

  public disconnectObservable: Observable<boolean>;

  constructor() {
    this.disconnectObservable = new Observable(observer => {
      // insert your logic here
      setTimeout(() => {
          observer.next('true');
      }, 1000);

      setTimeout(() => {
          observer.complete();
      }, 3000);
    });
  }
}

书中Dependency Injection in .NET 2nd edition (§6.3), Mark Seemann and I describe that Dependency cycles are often caused by Single Responsibility Principle违规。我的印象是,在您的具体情况下也是如此。当 class 有许多不是很内聚的方法时,通常会违反 SRP。

解决方案是将两个 classes AuthenticationServiceIdleService (或者甚至两者)中的任何一个拆分成更小的 classes。

我会说身份验证服务负责保存、管理和公开用户身份验证的状态。通过这个我是说授权服务根本不应该关心用户空闲。这是空闲服务的责任。

所以我会在 auth 服务中创建一个 BehaviorSubject 来广播用户身份验证的状态。空闲服务可以使用主题来确定空闲计时器何时需要start/stop。

export class AuthService {
    user: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

    logIn(){
        // logic to log user in
        this.user.next(true);
    }
    logOut(){
        // logic to log user out
        this.user.next(false);
    }
}

现在idle服务可以注入auth服务并决定如何处理idle定时器

export class IdleService {
    constructor(private authService: AuthService){
        this.authService.user.subscribe(res => {
            // watch user authentication state and determine how to handle idle timer
        });
    }

    idleOut(){
        this.authService.logOut();
    }
}

为此,您必须在应用程序加载时注入 IdleService(例如在 app.component 中,以便运行 IdleService 构造函数。我不确定这是否是最优雅的解决方案,但是这是首先想到的。这是一个非常基本的 stackblitz 演示这个概念。