在 getx 中使用 get_it 管理依赖注入

588 阅读3分钟

在 getx 中使用 get_it 管理依赖注入

视频

www.youtube.com/watch?v=NBo…

www.bilibili.com/video/BV1EG…

前言

原文 ducafecat.com/blog/use-ge…

上一节讲了 freezed 来强化模型 model 的功能。

今天来说下如何用 get_it 管理 getx 项目的依赖注入 Dependency Injection。

我将会改造我的 《woo实战课程》 代码来示范说明。

代码

github.com/ducafecat/f…

参考

pub-web.flutter-io.cn/packages/ge…

知识点

依赖注入(Dependency Injection,DI)是一种软件设计模式,用于管理对象之间的依赖关系。它是控制反转(Inversion of Control,IoC)设计模式的一种具体实现方式。

在传统的对象创建和依赖关系管理方式中,一个对象通常负责创建和管理其所依赖的其他对象。这样的设计可能导致代码之间的紧耦合,并且在测试时难以模拟和替换依赖的对象。

依赖注入通过将对象的创建和依赖关系的管理转移到外部,来解决这些问题。具体而言,依赖注入将对象的依赖通过构造函数、方法参数、属性注入等方式从外部注入到对象中,而不是由对象自身负责创建和管理依赖。这样可以实现对象之间的解耦,提高代码的可测试性、可维护性和可扩展性。

依赖注入的核心思想是:对象只关注自身的职责,而不需要关心如何创建和获取依赖的对象。依赖的对象由外部的容器或框架负责创建和注入进来。这样,对象在使用依赖时只需要声明它们的接口或抽象类,并通过依赖注入的方式获取具体的实现。

下面是一个简单的依赖注入示例:

 class Logger {
   void log(String message) {
     print(message);
   }
 }
 ​
 class UserService {
   final Logger _logger;
 ​
   UserService(this._logger);
 ​
   void login(String username, String password) {
     // 用户登录逻辑
     _logger.log('用户登录:$username');
   }
 }
 ​
 void main() {
   final logger = Logger();
   final userService = UserService(logger);
 ​
   userService.login('john', 'password');
 }

在上述代码中,UserService 类依赖于 Logger 类来记录日志。通过构造函数将 Logger 对象注入到 UserService 中,使得 UserService 可以在需要时使用 _logger 来记录日志。

通过依赖注入,UserService 类与 Logger 类之间实现了解耦,UserService 不需要关心 Logger 对象的创建和管理,只需要声明它所依赖的接口。这样,我们可以方便地替换或模拟 Logger 对象,以进行单元测试或灵活地切换不同的日志记录实现。

依赖注入的好处包括降低代码的耦合度、提高代码的可测试性和可维护性,以及增强代码的可扩展性和灵活性。它在许多现代的软件开发框架和库中得到广泛应用。

步骤

第一步:创建 getx 项目

猫哥这边使用 vscode 插件 "Flutter GetX Generator - 猫哥" 进行初始

不清楚的可以一进步阅读 《我写了个 vscode 插件提升 flutter getx 开发效率 79% | 猫哥

第二步:加入 get_it

添加组件

 $ flutter pub add get_it

工具类 lib/common/utils/wp_http.dart

 // 拉取数据 wordpress api
 class WPHttp {
   late Dio _dio;
 ​
   WPHttp() {
     // 初始 dio
     var options = BaseOptions(
       baseUrl: Constants.wpApiBaseUrl,
       connectTimeout: const Duration(seconds: 10), // 10000, // 10秒
       receiveTimeout: const Duration(seconds: 5), // 5000, // 5秒
       headers: {},
       contentType: 'application/json; charset=utf-8',
       responseType: ResponseType.json,
     );
     _dio = Dio(options);
 ​
     // 拦截器
     _dio.interceptors.add(RequestInterceptors());
   }
   
   ...

完整代码详见 github.com/ducafecat/f…

全局注入 lib/global.dart

 class Global {
   static final getIt = GetIt.instance;
   static Future<void> init() async {
     // 注册单例 - WPHttp
     getIt.registerSingleton<WPHttp>(WPHttp());
   }
 }

初始 main.dart

 Future<void> main() async {
   await Global.init();
   runApp(const MyApp());
 }

第三步:在 getx 控制器中使用

API 拉取数据 lib/common/api/product.dart

 import 'package:flutter_application_get_it/global.dart';
 ​
 import '../index.dart';
 ​
 /// 商品 api
 class ProductApi {
   // 读取单例 wphttp
   static final _getIt = Global.getIt<WPHttp>();
 ​
   /// 分类列表
   static Future<List<CategoryModel>> categories() async {
     var res = await _getIt.get(
       '/products/categories',
     );
 ​
     List<CategoryModel> categories = [];
     for (var item in res.data) {
       categories.add(CategoryModel.fromJson(item));
     }
     // 排序 menuOrder , 小号在前
     categories.sort((a, b) => a.menuOrder!.compareTo(b.menuOrder as int));
     return categories;
   }
   
   ...

Global.getIt() 通过泛型查找对象

控制器 lib/pages/product_list/controller.dart

 class ProductListController extends GetxController {
   ProductListController();
 ​
   // 商品列表
   List<ProductModel> products = [];
 ​
   _initData() async {
     products = await ProductApi.products(ProductsReq());
     update(["product_list"]);
   }
 ​
   void onTap() {}
 ​
   @override
   void onReady() {
     super.onReady();
     _initData();
   }
 }

视图 lib/pages/product_list/view.dart

   // 主视图
   Widget _buildView() {
     return ListView.builder(
       itemCount: controller.products.length,
       itemBuilder: (context, index) {
         return ListTile(
           title: Text(controller.products[index].name ?? ""),
           subtitle: Image.network(
             controller.products[index].images?[0].src ?? "",
             height: 100,
             fit: BoxFit.cover,
           ),
         );
       },
     );
   }
  @override
  Widget build(BuildContext context) {
    return GetBuilder<ProductListController>(
      init: ProductListController(),
      id: "product_list",
      builder: (_) {
        return Scaffold(
          appBar: AppBar(title: const Text("product_list")),
          body: SafeArea(
            child: _buildView(),
          ),
        );
      },
    );
  }

运行

代码

github.com/ducafecat/f…

小结

在项目中使用 get_it 可以单例工具类、懒加载业务类、工厂方式实例不同商品、异步初始需要 await 的对象、全局管理用户Auth登录认证、样式切换、等配置信息,而不是用 GetxService 对象。

感谢阅读本文

如果我有什么错?请在评论中让我知道。我很乐意改进。


flutter 学习路径


© 猫哥 ducafecat.com

end