避免循环依赖注入

时间:2017-12-13 17:21:31

标签: angular dependency-injection circular-dependency

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

  • 的AuthenticationService
  • IdleService

这两项服务相互依赖:

  1. 当我退出时,我必须停止观看用户空闲(通过调用IdleService中的方法)
  2. 当用户超时时,我必须从logout调用AuthenticationService方法来注销用户。
  3. 这种方法导致了循环依赖问题。您是否知道如何避免它或如何通过更好的方法改变我的实际方法?

3 个答案:

答案 0 :(得分:2)

在书Dependency Injection in .NET 2nd edition(§6.3)中,Mark Seemann和我描述了依赖周期通常是由Single Responsibility Principle违规造成的。我的印象是,在您的具体情况下也是如此。当一个类有很多不具有凝聚力的方法时,通常会违反SRP。

解决方案是将两个类public class TimeExtension : MarkupExtension, INotifyPropertyChanged { System.Threading.Timer _timer = null; public TimeExtension() { } public TimeExtension(TimeSpan interval) { Interval = interval; } public TimeSpan Interval { get; set; } = new TimeSpan(0, 0, 0, 0, 250); #region CurrentTime Property private DateTime _currentTime = default(DateTime); public DateTime CurrentTime { get { return _currentTime; } set { if (value != _currentTime) { _currentTime = value; OnPropertyChanged(); } } } #endregion CurrentTime Property public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] String propName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); public override object ProvideValue(IServiceProvider serviceProvider) { IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; if (provideValueTarget.TargetObject is DependencyObject targetobj) { if (provideValueTarget.TargetProperty is DependencyProperty targetProp) { System.Threading.TimerCallback tick = new System.Threading.TimerCallback(o => { try { CurrentTime = DateTime.Now; } catch (Exception ex) { _timer.Dispose(); _timer = null; } }); _timer = new System.Threading.Timer(tick, null, 0, (int)Interval.TotalMilliseconds); } } // This is how it must be done in WPF //return (new Binding("CurrentTime") { Source = this }).ProvideValue(serviceProvider); // Xamarin return new Binding("CurrentTime") { Source = this }; } } AuthenticationService中的任何一个(或者甚至两个)分成更小的类。

答案 1 :(得分:1)

我想说auth服务负责持有,管理和公开用户身份验证的状态。通过这个我说auth服务根本不应该关心用户空闲。这是空闲服务的责任。

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

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);
    }
}

现在,空闲服务可以注入auth服务并确定如何处理空闲计时器

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();
    }
}

为了实现这一点,你必须在app加载时注入IdleService(例如在app.component中运行IdleService构造函数方法。我不确定这是否是最优雅的解决方案,但这是第一件事我想到了这一点。这是一个非常基本的stackblitz演示这个概念。

答案 2 :(得分:0)

您可以在IdleService中创建一个观察者或主题,如果时间结束,则会返回断开连接消息。这样,只有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);
    });
  }
}