[译]Flutter 控制反转容器 kiwi

908 阅读4分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。

前言:

项目中使用了 Flutter 的控制反转容器 kiwi,然后在 Flutter 的 pub 上看了下 kiwi 的说明。
简单肉翻了一下,供自己以后参考。

kiwi | Dart Package (pub.dev)

Kiwi简介

一个适用于 Dart 和 Flutter 的简单却高效的控制反转容器。
该容器并不依赖反射,只是一个 Map,所以很快。

重要:使用该包需要 Dart2。

使用该包时,可以使用代码生成器,也可以不使用代码生成器。
代码生成器能使你更快地写代码,需要进行额外的配置(只安装一次)。
该章节只是关于 kiwi 的,包括控制反转容器和注解。
如果你在查找 kiwi_generator 的配置,可以在这里找到文档。

配置

pubspec.yaml添加kiwi的依赖。

dependencies:
  kiwi: ^4.0.1

2021/11/05 最新版本为4.0.1,需要指定适合自己项目的版本。

导入

在代码里添加下面的import:

import 'package:kiwi/kiwi.dart';

使用

Kiwi的核心是 KiwiContainer 类,这是所有的实例和 Factory 存放的地方。
KiwiContainer 是单例实现,可以如下访问这个单例:

KiwiContainer container = KiwiContainer();

即使这看上去像一个构造函数,但都会返回同一个实例。

如果想得到不同的容器实例,可以如下简单地创建范围容器:

KiwiContainer container = KiwiContainer.scoped();

它的工作机制和很多控制反转容器相似,可以注册某个类型的 Factory,然后解析类型来获得值。

注册

可以注册三种对象

实例

kiwi 可以如下注册简单的实例:

container.registerInstance(Sith('Anakin', 'Skywalker'));

也可以给一个特定的实例指定名称。

container.registerInstance(Sith('Anakin', 'Skywalker'), name: 'DartVader');

默认情况下,实例是用它们的类型来注册。如果想用父类来注册一个实例,只需要指定父类的泛型,子类的类型会被自动检测到。

container.registerInstance<Character>(Sith('Anakin', 'Skywalker'), name: 'DartVader');

上述例子中的CharacterSith 的父类。

Factories

container.registerFactory((c) => Sith('Anakin', 'Skywalker'));

也可以给一个特定的 Factory 指定名称。

container.registerFactory((c) => Sith('Anakin', 'Skywalker'), name: 'DartVader');

默认情况下,Factory 是用它们的返回类型来注册,如果想要注册父类的 Factory,需要指定父类 Facotry 的泛型。

参数c是 KiwiContainer 的实例,后面会看到它的使用方式(依赖多个 Service 时)。

单例

单例的注册和 Factory 相似,区别是只会被调用一次:第一次要获取单例的值的时候。

container.registerSingleton((c) => Sith('Anakin', 'Skywalker'));

解析

可以如下获取注册的实例:

Sith theSith = container.resolve<Sith>();

如果注册时指定了名称,可以如下获取实例的值:

Sith theSith = container.resolve<Sith>('DartVader');

如果注册时指定了父类,可以如下获取实例的值:

Sith theSith = container.resolveAs<Character, Sith>();

如果注册时指定了父类和名称,可以如下获取实例的值:

Sith theSith = container.resolveAs<Character, Sith>('DartVader');

KiwiContainer 是可调用类(即实例可以像函数那样被直接调用的类),可以如下解析某个类型:

Sith theSith = container<Sith>('DartVader');

依赖调用

如果有一个 Service 依赖其它 Service,则需要在构造函数里添加依赖。注册(其它)Service时,需要使用前面用于解析的参数 c(KiwiContainer 的实例)。

class Service {}

class ServiceA extends Service {}

class ServiceB extends Service {
  ServiceB(ServiceA serviceA);
}
...
// Registers a complex factory by resolving the dependency
// when the type is resolved.
KiwiContainer container = KiwiContainer();
container.registerFactory((c) => ServiceB(c.resolve<ServiceA>()));

如果 Service 需要很多依赖,写上面这种代码就显得乏味了。这个时候就需要代码生成器了。

注销

可以随时注销一个 Factory 或实例。

// Unregisters the Sith type.
container.unregister<Sith>();

// Unregister the Sith type that was registered under the name DartVader.
container.unregister<Sith>('DartVader');

清除

可以调用clear方法清除所有的已注册的类型。

container.clear();

开发模式下忽略 KiwiErrors

下列情况,kiwi 会默认抛出 KiwiError。

  • 用同一名称重复注册同一类型
  • 解析未被注册的类型
  • 注销未被注册的类型

这有助于避免生产环境中的潜在错误,即便你想要忽略这些 KiwiError。
要做到这一点,需要设置 KiwiContainer 的 silent 属性为 true

container.silent = true;

生产环境中,或者 silenttrue ,解析一个未注册的类型时,会返回 null。