如何在 flutter 中使用依赖注入?

How to use dependecy injection in flutter?

我想用di。在 flutter 中,我添加了这篇 https://pub.dartlang.org/packages/di packages my project and I started to read this https://webdev.dartlang.org/angular/guide/dependency-injection 文章,但我并不完全理解。

所以没关系: 在服务 class(例如:MyServices)上使用 @Injectable() 注解,但如何注入其他 class? 例如我想类似:

class MyClass{
   //some variable
   var asd = MyService.asd; //need inject var.
                            //maybe use injector.get(MyService).asd; 
                            //but how add injector? (I don't add across constructor)

   MyService.oneMethod;//need inject method
}

main(){
    var injector = new ModuleInjector([new Module()
       ..bind(MyService)
    ]);
}

重点是,我不想使用构造函数。我想直接使用注射器。这在 flutter/dart?

中是可能的

Angulars DI 包不能独立于 Angular 使用。

di 包已经过时并且依赖于 dart:mirrors 而在 Flutter 中不可用

似乎有一个新的 DI 包正在进行中,它应该取代 Angulars 内置的 DI,并且应该也可以在 Flutter 或服务器端应用程序中独立使用,但没有预-发布或源代码可用。

更新

宣布的 DI 包被无限期推迟。

如果您想将 class 用作单例,据我所知,常见的用例是使用工厂构造函数。

How do you build a Singleton in Dart?

现在从不需要在 Flutter 中使用任何依赖注入系统。

最近 open-sourced Google 有一个 Flutter-compatible 依赖注入框架。可在此处获得:https://github.com/google/inject.dart

本项目提供静态compile-time依赖注入,而不是依赖反射在run-time处注入依赖。如果你熟悉Dagger,它看起来很相似。

值得注意 - 这不是官方 Google 或 Dart 团队项目。在撰写本文时,文档很少,目前被视为开发人员预览版。

我在这里遇到了同样的问题,所以我专门为 Flutter 创建了一个 dart 包。它依赖于工厂方法而不是镜像api,所以它在 flutter 中工作。同时仍然使用熟悉的 IOC 模式。希望这对您有所帮助!

https://pub.dartlang.org/packages/flutter_simple_dependency_injection

import 'package:flutter_simple_dependency_injection/injector.dart';

void main() {
  final injector = Injector.getInjector();
  injector.map(Logger, (i) => new Logger(), isSingleton: true);
  injector.map(String, (i) => "https://api.com/", key: "apiUrl");
  injector.map(SomeService, (i) => new SomeService(i.get(Logger), i.get(String, "apiUrl")));

  injector.get(SomeService).doSomething();
  // passing in the [SomeService] as a generic parameter strongly types the return object.
  injector.get<SomeService>(SomeService).doSomething();
}

class Logger {
  void log(String message) => print(message); 
}

class SomeService {
  final Logger _logger;
  final String _apiUrl;

  SomeService(this._logger, this._apiUrl);

  void doSomething() {
    _logger.log("Doing something with the api at '$_apiUrl'");
  }
}

你好,这样的事情怎么样?很简单的实现,Injector 本身是单例的,也加入了 类 进去。当然可以很容易地扩展。如果您正在寻找更复杂的东西,请查看此包:https://pub.dartlang.org/packages/flutter_simple_dependency_injection

void main() {  
  Injector injector = Injector();
  injector.add(() => Person('Filip'));
  injector.add(() => City('New York'));

  Person person =  injector.get<Person>(); 
  City city =  injector.get<City>();

  print(person.name);
  print(city.name);
}

class Person {
  String name;

  Person(this.name);
}

class City {
  String name;

  City(this.name);
}


typedef T CreateInstanceFn<T>();

class Injector {
  static final Injector _singleton =  Injector._internal();
  final _factories = Map<String, dynamic>();

  factory Injector() {
    return _singleton;
  }

  Injector._internal();

  String _generateKey<T>(T type) {
    return '${type.toString()}_instance';
  }

  void add<T>(CreateInstanceFn<T> createInstance) {
    final typeKey = _generateKey(T);
    _factories[typeKey] = createInstance();
  }

  T get<T>() {
    final typeKey = _generateKey(T);
    T instance = _factories[typeKey];
    if (instance == null) {
      print('Cannot find instance for type $typeKey');
    }

    return instance;
  }
}

这个包 ioc_container 是一个 Dart Ioc 容器。从技术上讲,它不是注入器,因为它不会通过反射等方式自动注入。但是,它确实简化并组织了在您的工厂中注入依赖项的过程。这是代码。

代码here

import 'package:meta/meta.dart';

class ServiceDefinition<T> {
  bool isSingleton;
  T Function(IocContainer container) factory;

  ServiceDefinition(this.isSingleton, this.factory);
}

class IocContainer {
  @visibleForTesting
  final Map<Type, ServiceDefinition> serviceDefinitionsByType;
  @visibleForTesting
  final Map<Type, Object> singletons;

  IocContainer(this.serviceDefinitionsByType, this.singletons);

  ///Get an instance of your dependency
  T get<T>() => singletons.containsKey(T)
      ? singletons[T] as T
      : serviceDefinitionsByType.containsKey(T)
          ? (serviceDefinitionsByType[T]!.isSingleton
              ? singletons.putIfAbsent(
                  T,
                  () =>
                      serviceDefinitionsByType[T]!.factory(this) as Object) as T
              : serviceDefinitionsByType[T]!.factory(this))
          : throw Exception('Service not found');
}

///A builder for creating an [IocContainer].
class IocContainerBuilder {
  final Map<Type, ServiceDefinition> _serviceDefinitionsByType = {};

  ///Throw an error if a service is added more than once. Set this to true when
  ///you want to add mocks to set of services for a test.
  final bool allowOverrides;

  IocContainerBuilder({this.allowOverrides = false});

  ///Add a factory to the container.
  void addServiceDefinition<T>(

      ///Add a factory and whether or not this service is a singleton
      ServiceDefinition<T> serviceDefinition) {
    if (_serviceDefinitionsByType.containsKey(T)) {
      if (allowOverrides) {
        _serviceDefinitionsByType.remove(T);
      } else {
        throw Exception('Service already exists');
      }
    }

    _serviceDefinitionsByType.putIfAbsent(T, () => serviceDefinition);
  }

  ///Create an [IocContainer] from the [IocContainerBuilder].
  ///This will create an instance of each singleton service and store it
  ///in an immutable list unless you specify [isLazy] as true.
  IocContainer toContainer(
      {

      ///If this is true the services will be created when they are requested
      ///and this container will not technically be immutable.
      bool isLazy = false}) {
    if (!isLazy) {
      final singletons = <Type, Object>{};
      final tempContainer = IocContainer(_serviceDefinitionsByType, singletons);
      _serviceDefinitionsByType.forEach((type, serviceDefinition) {
        if (serviceDefinition.isSingleton) {
          singletons.putIfAbsent(
              type, () => serviceDefinition.factory(tempContainer));
        }
      });

      return IocContainer(
          Map<Type, ServiceDefinition>.unmodifiable(_serviceDefinitionsByType),
          Map<Type, Object>.unmodifiable(singletons));
    }
    return IocContainer(
        Map<Type, ServiceDefinition>.unmodifiable(_serviceDefinitionsByType),
        <Type, Object>{});
  }
}

extension Extensions on IocContainerBuilder {
  ///Add a singleton object dependency to the container.
  void addSingletonService<T>(T service) =>
      addServiceDefinition(ServiceDefinition(true, (i) => service));

  void addSingleton<T>(T Function(IocContainer container) factory) =>
      addServiceDefinition(ServiceDefinition(true, factory));

  void add<T>(T Function(IocContainer container) factory) =>
      addServiceDefinition(ServiceDefinition(false, factory));
}