「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。
前言:
项目中使用了 Flutter 的控制反转容器 kiwi,然后在 Flutter 的 pub 上看了下 kiwi 的说明。
简单肉翻了一下,供自己以后参考。
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');
上述例子中的Character 是 Sith 的父类。
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;
生产环境中,或者 silent 是 true ,解析一个未注册的类型时,会返回 null。