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实现切面编程,给需要检查的方法标记注解,自动在方法执行前触发检查:
- 添加依赖:
dependencies: reflectable: ^4.0.0
- 定义注解:
class CheckInit extends Reflectable { const CheckInit() : super(methodInvokeCapability); } const checkInit = CheckInit();
- 给业务方法标记注解:
@checkInit Future<bool> openAppSettings() async { return _locationRepository.openAppSettings(); }
- 实现拦截逻辑:通过反射监听方法调用,在执行前自动调用
_handleInitError。注意:反射在Flutter Release模式下需要额外配置,可能影响性能。
方案4:开发阶段断言检查(仅调试用)
如果仅需在开发阶段提醒自己,可用断言替代手动调用,Release模式下断言会自动失效:
Future<bool> openAppSettings() async { assert(() { _handleInitError(); return true; }()); return _locationRepository.openAppSettings(); }
内容的提问来源于stack exchange,提问作者Baran
相关产品推荐
相关产品推荐

