Flutter依赖注入插件zef_di_core的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter依赖注入插件zef_di_core的使用

zef_di_core 是一个用于依赖注入的Dart库,它提供了一组抽象接口和默认实现。这个项目是 zef_di_abstractionszef_di_inglue 的延续。如果你还在使用这些库,建议升级到这个新的版本。

特性

  • 框架无关:设计为一个灵活的包装器,可以与任何依赖注入(DI)框架一起使用,提供统一的服务注册和解析接口。
  • 多服务解析:支持解析注册在相同接口下的多个服务,增强了复杂应用中的服务检索灵活性。
  • 自定义适配器集成:允许用户通过编写自定义适配器来集成任何外部DI框架,确保兼容性并根据项目需求扩展功能。
  • 无限参数:与其他DI框架不同,我们提供了在解析依赖时传递任意数量参数的能力。
  • 代码生成:自动化的依赖注册和解析。

定义

Singleton

单例是存储在内存中并每次解析依赖时重用的实例。这使得它们非常快,但占用大量内存。请注意,当你手动销毁对象(或通过外部包销毁)后,引用仍然存在于DI框架中,但会抛出异常。

Transient

瞬态注册就像注册一个每次请求对象时都会调用的函数。这种方式内存使用量最小,因为没有缓存实例,但在每次请求时都会实例化对象,可能会导致性能问题。

Lazy

懒加载是单例和瞬态的结合。你将注册一个工厂,该工厂将在首次解析类型时调用,然后实例将存储在内存中。这样,你总是可以获取相同的实例。

入门

初始化和使用

我们喜欢“建造者”模式,所以这是初始化服务定位器的方法。在你的 main() 函数中,像这样调用它:

void main() {
  ServiceLocatorBuilder()
    .build();

  // 应用逻辑
}

你可以通过 ServiceLocator.instance 或简写 ServiceLocator.I 访问它。

单例

简单注册

要注册一个单例,直接传递你想要注册的对象实例:

ServiceLocator.I.registerSingleton(Dolphin());

要解析该实例,调用 resolve() 方法:

final Dolphin dolphin = ServiceLocator.I.resolve<Dolphin>();

注意

你可以多次注册相同的实例,如果已经在 ServiceLocatorConfig 中设置了此选项。默认情况下是开启的。resolve() 方法将返回第一个注册的实例,但你可以通过以下方式获取最后一个注册的实例:

final Dolphin dolphin = ServiceLocator.I.resolve<Dolphin>(resolveFirst: false);

相同的原理适用于以下注册选项。

使用工厂注册

你也可以使用工厂注册单例:

ServiceLocator.I.registerSingletonFactory<MyService>(
  (args) => MyService(),
);

这样你就可以更灵活地控制实例创建。注意,工厂只会被调用一次,并且是在注册后立即调用的。

命名注册

你可以为注册传递一个名称:

ServiceLocator.I.registerSingleton(Dolphin(), name: 'One');
ServiceLocator.I.registerSingleton(Dolphin(), name: 'Two');

这样你可以轻松解析不同的实例:

final Dolphin dolphin = ServiceLocator.I.resolve<Dolphin>(name: 'one'); // 返回名为 `one` 的实例
final Dolphin dolphin = ServiceLocator.I.resolve<Dolphin>(name: 'two'); // 返回名为 `two` 的实例

键值注册

键值注册与命名注册类似,但使用不同的属性。

环境注册

环境注册也与命名注册类似,但用于定义不同环境(如 “dev”, “test”, “prod”)下的实例。

瞬态注册

简单注册

ServiceLocator.I.registerTransient<MyService>(
  (args) => MyService(),
);

解析时,你像处理单例一样操作:

final MyService myService = ServiceLocator.I.resolve<MyService>();

带参数解析

瞬态工厂的一个特性是你可以在解析实例时传递参数。首先,你需要告诉框架如何解析工厂:

ServiceLocator.I.registerTransient<UserService>(
  (Map<String, dynamic> args) => UserService(
    id: args['theUserId'] as UserId, // 这是参数提供的方式
    username: args['theUsername'], // 你不需要指定类型
    password: args['thePassword'] as String, // 但必须传递所有所需参数
  ),
);

args 参数是一个映射表,你在尝试解析工厂时传递的参数:

final UserService userService = ServiceLocator.I.resolve<UserService>(
  args: {
    'theUserId': UserId('1'),
    'theUsername': 'HansZimmer123',
    'thePassword': 'blafoo1!',
  },
);

如果你没有传递必需的参数,将会抛出 TypeError

懒加载注册

ServiceLocator.I.registerLazy<MyLazyService>(
  Lazy<MyLazyService>(() => MyLazyService()),
);

解析懒加载注册的服务时,使用相同的解析方法:

final MyLazyService myLazyService = ServiceLocator.I.resolve<MyLazyService>();

自定义适配器的实现

这个包附带了一个内置适配器,应该能满足大部分需求,但你仍然可以开发自己的适配器以获得完全控制。这是一个概念性的示例来指导你:

class MyDIAdapter extends ServiceLocatorAdapter {
  // 使用你选择的DI框架实现适配器方法
}

更多关于Flutter依赖注入插件zef_di_core的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter依赖注入插件zef_di_core的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用zef_di_core插件进行依赖注入的示例代码。zef_di_core是一个用于依赖注入的插件,它可以帮助你管理应用程序中的依赖关系,使代码更加模块化和易于测试。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加zef_di_core依赖:

dependencies:
  flutter:
    sdk: flutter
  zef_di_core: ^最新版本号

确保你替换了最新版本号为当前可用的最新版本。

2. 配置依赖注入容器

在你的Flutter项目中,你需要创建一个依赖注入容器。通常,你会在应用程序的入口点(如main.dart)进行此操作。

import 'package:flutter/material.dart';
import 'package:zef_di_core/zef_di_core.dart';

// 假设你有两个服务类
class MyService {
  void doSomething() {
    print("Service is doing something!");
  }
}

class AnotherService {
  final MyService myService;

  AnotherService(this.myService);

  void doAnotherThing() {
    myService.doSomething();
    print("Another service is doing another thing!");
  }
}

void main() {
  // 创建依赖注入容器
  final diContainer = DiContainer();

  // 注册服务
  diContainer.register<MyService>(() => MyService());
  diContainer.register<AnotherService>(
    () => AnotherService(diContainer.resolve<MyService>())
  );

  runApp(
    DiWidget(
      container: diContainer,
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

3. 在Widget中使用依赖注入

现在,你可以在Widget中通过依赖注入容器获取服务实例。这里我们假设在HomeScreen中使用AnotherService

import 'package:flutter/material.dart';
import 'package:zef_di_core/zef_di_core.dart';

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 使用DiContainer.of方法获取依赖注入容器
    final diContainer = DiContainer.of(context);
    final anotherService = diContainer.resolve<AnotherService>();

    return Scaffold(
      appBar: AppBar(
        title: Text('Home Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            anotherService.doAnotherThing();
          },
          child: Text('Press me'),
        ),
      ),
    );
  }
}

完整代码

import 'package:flutter/material.dart';
import 'package:zef_di_core/zef_di_core.dart';

// 服务类
class MyService {
  void doSomething() {
    print("Service is doing something!");
  }
}

class AnotherService {
  final MyService myService;

  AnotherService(this.myService);

  void doAnotherThing() {
    myService.doSomething();
    print("Another service is doing another thing!");
  }
}

void main() {
  final diContainer = DiContainer();

  diContainer.register<MyService>(() => MyService());
  diContainer.register<AnotherService>(
    () => AnotherService(diContainer.resolve<MyService>())
  );

  runApp(
    DiWidget(
      container: diContainer,
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final diContainer = DiContainer.of(context);
    final anotherService = diContainer.resolve<AnotherService>();

    return Scaffold(
      appBar: AppBar(
        title: Text('Home Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            anotherService.doAnotherThing();
          },
          child: Text('Press me'),
        ),
      ),
    );
  }
}

这个示例展示了如何使用zef_di_core插件在Flutter项目中进行依赖注入。通过这种方法,你可以轻松管理应用程序中的依赖关系,使代码更加模块化和易于维护。

回到顶部