Flutter 插件vader_di的使用_vader_di是一个简单、灵活且平台无关的依赖注入库,具有方便的语法
Flutter 插件vader_di的使用_vader_di是一个简单、灵活且平台无关的依赖注入库,具有方便的语法
vader_di
一个简单、灵活且平台无关的依赖注入库,具有方便的语法。请注意,它只是一个核心库,不使用反射、代码生成或包装器来轻松集成到不同的Dart项目中。
如果你需要Flutter集成,请查找包vader_flutter。 它包含用于控制反转原则的Widget包装器和帮助程序。
新闻
新酷特性 - 自定义工厂。在容器配置时间未知的情况下创建和销毁带有参数的对象。文档将很快更新。
开始使用
主要类是DiContainer
。你可以通过获取ResolvingContext
并通过bind<T>()
方法来注册你的依赖项,并使用不同的解析变体方法。接下来,你可以通过resolve<T>()
获取依赖项。例如:
final container = new DiContainer();
container.bind<SomeService>().toValue(new SomeServiceImplementation());
// 它只是返回之前注册的实例
final someService = container.resolve<SomeService>();
懒加载构造
通常,你在一个真正需要的地方创建某个对象的实例。因此,你可以通过from
方法使用懒加载(即按需)构造对象。例如:
final container = new DiContainer();
// 在from方法中,你只需定义如何通过工厂lambda构造一个实例
container.bind<SomeService>().from(() => new SomeService());
// 每次调用时,它都会通过已注册的工厂lambda构造一个实例
final someService = container.resolve<SomeService>();
final anotherSomeService = container.resolve<SomeService>();
assert (someService != anotherSomeService);
但是,通常你有许多类型,它们具有不同的依赖关系,这些依赖关系形成了依赖图。例如:
class A {}
class B {}
class C {
final A a;
final B b;
C(this.a, this.b);
}
如果你需要注册依赖于容器中其他类型的类型,你可以使用from1<T1>
- from8<T1...T8>
方法,其中数字表示通过类型参数请求的依赖项数量。注意,你需要在类型参数中定义所有依赖项 - from2<A1, A2>
。例如:
class SomeService {
final A a;
final B b;
SomeService(this.a, this.b)
}
final container = new DiContainer();
container.bind<A>().from(() => new A());
container.bind<B>().from(() => new B());
/// 现在在工厂lambda中,你定义如何通过其他依赖项构造依赖项(解决的实例顺序根据类型参数的顺序)
/// 注意!每次调用SomeService解析时,它都会创建新的A和B实例
container.bind<SomeService>().from2<A, B>((a, b) => new SomeService(a, b));
final someService = container.resolve<SomeService>();
实例生命周期和范围控制
但是,如果你只想一次创建已注册依赖项的实例,但在容器中需要多次获取/解析它,该怎么办?单例模式?天哪,禁止!
你可以通过asSingleton()
添加注册你的依赖项。例如:
final container = new DiContainer();
container.bind<A>()
.from(() => new A())
.asSingleton();
container
.bind<B>()
.from(() => new B())
.asSingleton();
container.bind<SomeService>().from2<A, B>((a, b) => SomeService(a, b));
// 上面的代码意味着:容器,请仅在第一次请求时注册A和B的创建,
// 并在每次请求SomeService时注册其创建。
final a = container.resolve<A>();
final b = container.resolve<B>();
final anotherA = container.resolve<A>();
final anotherB = container.resolve<B>();
assert(a == anotherA && b == anotherB);
final someService = container.resolve<SomeService>();
final anotherSomeService = container.resolve<SomeService>();
assert(someService != anotherSomeService);
如果你希望立即构造已注册的实例,可以调用resolve()
。例如:
final container = new DiContainer();
// 它将在注册后强制解析依赖项的创建
container.bind<SomeService>()
.from(() => new SomeService())
.asSingleton()
.resolve();
当处理复杂应用时,在大多数情况下你会处理许多模块,每个模块都有自己的依赖项。这些模块可以通过不同的DiContainer
进行配置。因此,你需要将应用程序与多个容器组合在一起。在Vader中这不成问题,因为你可以将容器附加到另一个作为父级。在这种情况下,父容器的依赖项对子容器可见,从而可以形成不同的依赖项范围。例如:
final parentContainer = new DiContainer();
parentContainer.bind<A>().from(() => new A());
final childContainer = new DiContainer(parentContainer);
// 注意,父依赖项A对子容器可见
final a = childContainer.resolve<A>();
/*
// 但以下代码会抛出错误,因为父容器不知道其子容器。
final parentContainer = new DiContainer();
final childContainer = new DiContainer();
childContainer.bind<A>().from(() => new A());
// 抛出错误
final a = parentContainer.resolve<A>();
*/
在某些情况下,你的类可能会捕获一些资源或订阅,你希望在使用实例后关闭。为此,你可以通过withDispose()
注册清理策略,该策略将在容器的dispose
方法被调用时调用。请注意,如果你定义了清理策略,容器将跟踪所有已解析的实例,并在其被清理时调用它们的清理方法。例如:
final container = DiContainer();
container.bind<A>()
.from(() => new A())
.withDispose((a) => a.dispose());
final a = container.resolve<A>();
final anotherA = container.resolve<A>();
/// a 和 anotherA 将被清理
container.dispose();
请注意,清理策略不会影响容器的子容器或父容器。因此,如果你想清理整个容器树,你需要单独清理每个子容器。
库设计
库设计非常简单。它由DiContainer
和Resolver
s组成。DiContainer
是一个包含不同类型的所有Resolver
s的容器。而Resolver
只是一个知道如何解析给定类型的对象。许多解析器被其他解析器装饰,以便可以根据不同的用例进行组合。Resolver
是一个抽象类,因此有许多实现。主要的一个是ResolvingContext
。你可以将其视为具有帮助方法的上下文对象,用于创建不同的解析变体(如from
、toValue
、asSingleton
、withDispose
等)。但它们都只是使用toResolver
方法来定义某些根解析器。
下面是一个例子(来自example.dart
):
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:vader_di/vader.dart';
void main() async {
final dataModule = new DiContainer()
..bind<ApiClient>().toValue(new ApiClientMock())
..bind<DataService>().from1<ApiClient>((c) => new NetworkDataService(c))
..bind<DataBloc>().from1<DataService>((s) => new DataBloc(s));
final dataBloc = dataModule.resolve<DataBloc>();
dataBloc.data.listen(
(d) => print('Received data: $d'),
onError: (e) => print('Error: $e'),
onDone: () => print('DONE')
);
await dataBloc.fetchData();
}
class DataBloc {
final DataService _dataService;
Stream<String> get data => _dataController.stream;
StreamController<String> _dataController = new StreamController.broadcast();
DataBloc(this._dataService);
Future<void> fetchData() async {
try {
_dataController.sink.add(await _dataService.getData());
} catch (e) {
_dataController.sink.addError(e);
}
}
void dispose() {
_dataController.close();
}
}
abstract class DataService {
Future<String> getData();
}
class NetworkDataService implements DataService {
final ApiClient _apiClient;
final _token = '12345';
NetworkDataService(this._apiClient);
[@override](/user/override)
Future<String> getData() async =>
await _apiClient.sendRequest(
url: 'www.data.com',
token: _token,
requestBody: { 'type' : 'data' });
}
abstract class ApiClient {
Future sendRequest({[@required](/user/required) String url, String token, Map requestBody});
}
class ApiClientMock implements ApiClient {
[@override](/user/override)
Future sendRequest({[@required](/user/required) String url, String token, Map requestBody}) async {
return 'mock body';
}
}
更多关于Flutter 插件vader_di的使用_vader_di是一个简单、灵活且平台无关的依赖注入库,具有方便的语法的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter 插件vader_di的使用_vader_di是一个简单、灵活且平台无关的依赖注入库,具有方便的语法的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,基于帖子中提到的“Flutter未知功能插件vader_di”且其功能为“基于名称的合理推测”,我们可以尝试从插件名称“vader_di”进行一些合理的推测。通常,“DI”在软件开发中常指“Dependency Injection”(依赖注入),这是一个用于实现控制反转(IoC)的设计模式。
以下是一个假设性的Flutter插件使用示例,假设vader_di
是一个用于依赖注入的插件。请注意,由于这是一个假设性的示例,实际插件的使用可能有所不同。
假设性的Flutter插件vader_di
使用示例
-
添加依赖
首先,在
pubspec.yaml
文件中添加vader_di
作为依赖:dependencies: flutter: sdk: flutter vader_di: ^x.y.z # 替换为实际版本号
然后运行
flutter pub get
来安装依赖。 -
设置依赖注入容器
假设
vader_di
提供了一个依赖注入容器,我们可以这样设置它:import 'package:vader_di/vader_di.dart'; // 假设这是插件的导入路径 class MyService { void doSomething() { print("Doing something in MyService"); } } void main() { // 初始化依赖注入容器 final container = DIContainer(); // 注册依赖 container.register<MyService>(() => MyService()); // 解析依赖 final myService = container.resolve<MyService>(); myService.doSomething(); // 输出: Doing something in MyService }
-
在Flutter Widget中使用
假设我们有一个Flutter应用,并希望在Widget中使用依赖注入:
import 'package:flutter/material.dart'; import 'package:vader_di/vader_di.dart'; // 假设这是插件的导入路径 class MyApp extends StatelessWidget { final DIContainer _container; MyApp(this._container); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(_container.resolve<MyService>()), ); } } class MyHomePage extends StatelessWidget { final MyService _myService; MyHomePage(this._myService); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Demo Home Page'), ), body: Center( child: ElevatedButton( onPressed: () { _myService.doSomething(); }, child: Text('Call MyService'), ), ), ); } } void main() { final container = DIContainer(); container.register<MyService>(() => MyService()); runApp(MyApp(container)); }
注意事项
- 以上代码是一个假设性的示例,实际插件
vader_di
的API可能与此不同。 - 请务必查阅插件的官方文档或源代码,以了解实际的使用方法和API。
- 如果插件
vader_di
不存在或不是一个用于依赖注入的插件,那么以上代码将不适用。
希望这个假设性的示例对你有所帮助!如果有更多关于Flutter或依赖注入的问题,欢迎继续提问。