2

在 Flutter 中,我对如何为类创建参数以及如何创建这些参数的最佳方式感到有些迷茫。通常,参数只是注入另一个类以执行任务的类。这些参数如何在功能方面创建似乎并不重要,因为代码适用于各种创建方法。我看到网上人们谈论服务定位器、单例、依赖注入。Riverpod 在网站上声明“提供者完全替代了单例、服务定位器、依赖注入或继承小部件等模式。” 所以我想我不需要服务定位器,因为我使用的是 Riverpod。但是,我在网上找不到任何关于如何向 Riverpod 提供程序注入服务的信息。我可以看到您可以阅读没有上下文的提供程序ProviderContainer().read但这是用作服务注入吗?这是一个单身人士这么多的服务定位器?在 Riverpod 示例中,它声明您不需要ProviderContainer().readFlutter,这听起来不像是服务定位器之类的替代品:

  // Where the state of our providers will be stored.
  // Avoid making this a global variable, for testability purposes.
  // If you are using Flutter, you do not need this.
  final container = ProviderContainer();

这是一个代码示例,类中的一个字段是一个 ViewModel,它将一些用例作为参数。这里的用例是领域层操作类,它们调用存储库来执行 API 请求或本地存储操作等外部操作。

  final CreateUserViewModel createUserViewModel =
      CreateUserViewModel(SavePasswordLocallyUseCase(), CreateUserUseCase());
...

所以我只是在字面上创建了它们,就像SavePasswordLocallyUseCase(),以便注入它们。这绝对是最简单的方法,代码最少。我想它可能效率较低,因为它每次都在创建一个新的,尽管我认为这通常不会产生明显的差异。这些以这种方式创建的参数会被垃圾收集器清理掉吗?这样做的后果是什么?

如果我必须注入一个类型AuthenticationService,我应该使用服务定位器还是内联创建它们AuthenticationService(),或者使用 Riverpod 的ProviderContainer.read()

4

1 回答 1

2

环顾四周后,我可以看到 Flutter 中的依赖注入主要是通过创建一个新的参数实例来注入到构造函数中,就像我的问题一样:

final CreateUserViewModel createUserViewModel =
  CreateUserViewModel(SavePasswordLocallyUseCase(), CreateUserUseCase());

如果注入的类也需要注入自己的参数,这会很快变得非常混乱。依赖注入包的主要目的是通过设置类及其所需的参数来解决这个问题,然后您可以从依赖注入包中请求实例,而无需再次创建其构造函数参数。ProviderContainer.read()我相信如果不在 UI 层中,它的 Riverpod 版本确实可以使用。假设我想实例化一个在其构造函数中采用存储库的类:

class SavePasswordLocallyUseCase implements ISavePasswordLocallyUseCase {
  const SavePasswordLocallyUseCase(this._userRepository);
  final IRegistrationRepository _userRepository;
  String invoke(String password, String confirmPassword) {
    return _userRepository.putPasswords(password, confirmPassword);
  }

注入的存储库本身需要 2 个构造函数参数:

class RegistrationRepository implements IRegistrationRepository {
  const RegistrationRepository(
      this._authenticationRemoteDataSource, this._registrationLocalDataSource);
    }
  final AuthenticationRemoteDataSource _authenticationRemoteDataSource;

  final IRegistrationLocalDataSource _registrationLocalDataSource;

而不是像这样实例化类:

new RegistrationRepository(AuthenticationRemoteDataSource(X()), RegistrationLocalDataSource(Y()))

Provider通过在 Riverpod 中创建一个将参数实例化一次的库存标准:

final registrationRepositoryProvider =
    Provider.autoDispose<RegistrationRepository>((ref) {
  ref.onDispose(() {
    print('disposing');
  });

  return RegistrationRepository(
      AuthenticationRemoteDataSource(X()), RegistrationLocalDataSource(Y()));
});

然后我可以允许类访问RegistrationRepository这样的:

ref.container.read(registrationRepositoryProvider);

或者没有 ProviderReference:

ProviderContainer().read(registrationRepositoryProvider);

我仍然不确定 Riverpod 中的延迟加载和单例,以及这些选项是否可行。将Injectable用于不在视图中的 DI可能更可配置,我正在考虑。

于 2020-12-11T23:15:23.153 回答