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

请注意,清理策略不会影响容器的子容器或父容器。因此,如果你想清理整个容器树,你需要单独清理每个子容器。

库设计

库设计非常简单。它由DiContainerResolvers组成。DiContainer是一个包含不同类型的所有Resolvers的容器。而Resolver只是一个知道如何解析给定类型的对象。许多解析器被其他解析器装饰,以便可以根据不同的用例进行组合。Resolver是一个抽象类,因此有许多实现。主要的一个是ResolvingContext。你可以将其视为具有帮助方法的上下文对象,用于创建不同的解析变体(如fromtoValueasSingletonwithDispose等)。但它们都只是使用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

1 回复

更多关于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使用示例

  1. 添加依赖

    首先,在pubspec.yaml文件中添加vader_di作为依赖:

    dependencies:
      flutter:
        sdk: flutter
      vader_di: ^x.y.z  # 替换为实际版本号
    

    然后运行flutter pub get来安装依赖。

  2. 设置依赖注入容器

    假设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
    }
    
  3. 在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或依赖注入的问题,欢迎继续提问。

回到顶部