在 flutter 上使用 get_it 对抗循环依赖?

Pie*_*LOT 1 circular-dependency dart flutter

GetIt 是Dart 和 Flutter 项目的服务定位器( https://github.com/fluttercommunity/get_it )

我认为 GetIt 应该为我们提供一些有关循环依赖的详细信息。

例如,当我运行测试时,存在无限循环并且永远不会结束。

Abi*_*n47 7

get_it 用于定义全局对象和服务,并提供用于访问它们的定位器功能。如果您的全局服务之间存在循环依赖关系,那么您很可能已将这些服务设计为彼此紧密耦合。例如:

class ServiceA {
  final ServiceB b;

  ServiceA(this.b);

  void foo() {
    b.bar();
  }

  void bar() { ... }
}

class ServiceB {
  final ServiceA a;

  ServiceB(this.a);

  void foo() {
    a.bar();
  }

  void bar() { ... }
}

// GetIt Initialization

GetIt g = GetIt.instance;
g.registerLazySingleton<ServiceA>(() => ServiceA(g.get<ServiceB>()));
g.registerLazySingleton<ServiceB>(() => ServiceB(g.get<ServiceA>()));
Run Code Online (Sandbox Code Playgroud)

此后,调用GetIt.I.get定位ServiceAServiceB可能会创建由循环依赖引起的无限循环。通过这种实现,没有真正的方法可以防止循环而不陷入检查和延迟执行的兔子洞。

循环依赖的真正解决方案通常很简单:设计您的应用程序时首先不要有它。例如,在上面的示例中,在构造函数中ServiceA具有严格的依赖关系ServiceB,反之亦然。相反,服务可以使用服务定位器来在执行需要的方法期间获取对必要服务的引用。换句话说,我们已经在使用 get_it,那么为什么不在此处使用它呢?

class ServiceA {
  ServiceA();

  void foo() {
    final b = GetIt.I.get<ServiceB>();
    b.bar();
  }

  void bar() { ... }
}

class ServiceB {
  ServiceB();

  void foo() {
    final a = GetIt.I.get<ServiceA>();
    a.bar();
  }
}

// GetIt Initialization

GetIt g = GetIt.instance;
g.registerLazySingleton<ServiceA>(() => ServiceA());
g.registerLazySingleton<ServiceB>(() => ServiceB());
Run Code Online (Sandbox Code Playgroud)

ServiceA现在,和彼此之间的依赖关系ServiceB更加动态,并且不依赖于它们各自的构造函数。不再存在循环依赖问题,并且 get_it 初始化程序在访问单例时初始化它们不会出现问题。

  • @Pierre-LucBLOT get_it 本身如何能够检测循环依赖关系?定位器/初始化程序无法在没有反射的情况下获取有关类型本身的信息。任何检测方法(包括您的)都要求类型本身实现自定义 getter 方法。也许该包可以提供该实用程序,但循环检测仅适用于实际使用它的类型。这是一个非常小众的功能,需要人们真正了解它才能实现,即使这样它也只提供运行时错误而不是任何实际的保护。 (3认同)