首页 > 解决方案 > 在颤振上使用 get_it 对抗循环依赖?

问题描述

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

我认为 GetIt 应该给我们一些关于循环依赖的细节。

例如,当我运行我的测试时,会有一个无限循环,它们永远不会结束。

标签: flutterdartcircular-dependency

解决方案


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

在此之后,调用GetIt.I.get目标ServiceA或者ServiceB可能会创建由循环依赖引起的无限循环。有了这个实现,没有真正的方法可以防止循环,而不会进入检查和延迟执行的兔子洞。

循环依赖的真正解决方案通常很简单:将您的应用设计为一开始就没有它。例如,在上面的例子中,在构造函数中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<ServiceA>(() => ServiceB());

现在,彼此之间的依赖关系更加动态,并且不依赖于它们各自的构造函数ServiceAServiceB不再存在循环依赖问题,并且 get_it 初始化器在访问单例时将没有问题。


推荐阅读