You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart/Flutter单例中如何实现调用方法前自动执行初始化检查?

问题描述

我在Dart/Flutter中使用单例模式,已实现依赖注入与参数注入逻辑,并编写了_handleInitError方法用于检查依赖和参数是否完成注入。目前需在所有业务方法中手动调用该方法,请问是否有更优方案?能否实现调用任意业务方法前自动执行该检查方法?


相关实现代码

单例与依赖注入逻辑

LocalizationClientComponent._();

/// Singleton instance of the [LocalizationClientComponent] class.
static final instance = LocalizationClientComponent._();

static bool _injectedDependencies = false;

static bool _injectedParams = false;

late final DeviceInfoRepository _deviceInfoRepository;
late final MapapiRepository _mapapiRepository;
late final SensorsRepository _sensorsRepository;
late final LocationRepository _locationRepository;
late final BluetoothRepository _bluetoothRepository;
late final WifiRepository _wifiRepository;

void injectDependencies({
  required DeviceInfoRepository deviceInfoRepository,
  required MapapiRepository mapapiRepository,
  required SensorsRepository sensorsRepository,
  required LocationRepository locationRepository,
  required BluetoothRepository bluetoothRepository,
  required WifiRepository wifiRepository,
}) {
  if (_injectedDependencies) return;

  _deviceInfoRepository = deviceInfoRepository;
  _mapapiRepository = mapapiRepository;
  _sensorsRepository = sensorsRepository;
  _locationRepository = locationRepository;
  _bluetoothRepository = bluetoothRepository;
  _wifiRepository = wifiRepository;

  _injectedDependencies = true;
}

参数注入逻辑

void injectParams({
  required String email,
  required String password,
  required Duration postFrequency,
  required int sensorListLength,
}) {
  if (_injectedParams) return;

  _postFrequency = postFrequency;
  _sensorListLength = sensorListLength;
  _telemetryEvent = TelemetryEvent(_sensorListLength);

  _injectedParams = true;
}

初始化检查方法

void _handleInitError() {
  final StringBuffer errorMessage = StringBuffer();
  if (!_injectedDependencies) {
    errorMessage
      ..write(
        'Dependencies are not injected. Use injectDependencies() before using any other methods.',
      )
      ..write('\n');
  }

  if (!_injectedParams) {
    errorMessage.write(
      'Parameters are not injected. Use injectParams() before using any other methods.',
    );
  }

  if (errorMessage.isNotEmpty) {
    throw Exception(errorMessage.toString());
  }
}

当前业务方法调用方式

Future<bool> openAppSettings() async {
  _handleInitError();

  return _locationRepository.openAppSettings();
}

Future<bool> openLocationSettings() async {
  _handleInitError();

  return _locationRepository.openLocationSettings();
}

Future<bool> requestLocationPermission() {
  _handleInitError();

  return _locationRepository.requestLocationPermission();
}

Future<bool> activateLocationService() async {
  _handleInitError();

  return _locationRepository.activateLocationService();
}

Future<bool> turnOnWifi() async {
  _handleInitError();

  return _wifiRepository.turnOnWifi();
}

解决方案

方案1:重构单例获取逻辑(推荐)

直接把检查逻辑整合到单例实例的获取入口,确保任何时候获取实例时都自动完成初始化检查,从根源上避免业务方法重复调用:

// 私有化实例,不再直接暴露
static LocalizationClientComponent? _instance;

// 对外提供带检查的实例获取方法
static LocalizationClientComponent get instance {
  _handleInitError();
  return _instance!;
}

// 修改注入方法,完成依赖/参数注入后再初始化实例
void injectDependencies({...}) {
  if (_injectedDependencies) return;
  _instance = LocalizationClientComponent._();
  // 赋值依赖逻辑...
  _injectedDependencies = true;
}

void injectParams({...}) {
  if (_injectedParams) return;
  // 赋值参数逻辑...
  _injectedParams = true;
}

之后业务方法无需手动调用_handleInitError,只要通过LocalizationClientComponent.instance调用方法,就会自动触发检查。

方案2:代理模式分离检查与业务逻辑

把业务方法私有化,对外暴露的方法统一做检查后转发调用,减少重复代码:

// 私有业务逻辑方法
Future<bool> _openAppSettings() async {
  return _locationRepository.openAppSettings();
}

// 对外公开方法,统一执行检查
Future<bool> openAppSettings() async {
  _handleInitError();
  return _openAppSettings();
}

这种方式将检查逻辑和业务逻辑分离,后续修改检查逻辑只需调整一处。

方案3:利用Dart反射实现AOP(适合大量方法场景)

借助第三方包reflectable实现切面编程,给需要检查的方法标记注解,自动在方法执行前触发检查:

  1. 添加依赖:
dependencies:
  reflectable: ^4.0.0
  1. 定义注解:
class CheckInit extends Reflectable {
  const CheckInit() : super(methodInvokeCapability);
}

const checkInit = CheckInit();
  1. 给业务方法标记注解:
@checkInit
Future<bool> openAppSettings() async {
  return _locationRepository.openAppSettings();
}
  1. 实现拦截逻辑:通过反射监听方法调用,在执行前自动调用_handleInitError。注意:反射在Flutter Release模式下需要额外配置,可能影响性能。

方案4:开发阶段断言检查(仅调试用)

如果仅需在开发阶段提醒自己,可用断言替代手动调用,Release模式下断言会自动失效:

Future<bool> openAppSettings() async {
  assert(() {
    _handleInitError();
    return true;
  }());
  return _locationRepository.openAppSettings();
}

内容的提问来源于stack exchange,提问作者Baran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:01:17