这是什么 需求描述 需求就是为了项目间解耦, 需要一个简单的DI工具 目标是可以直接通过代码直接能提示出目前已经注册好的类
当前情况 目前已有的方案是直接用一个类常驻内存作为一个中转站 使用效果为
1 2 3 4 5 6 7 8 9 SharedStateStore().set <VideoRewardWrapper>( PredefinedKeys.videoRewardManager, VideoRewardManager()); SharedStateStore().get <VideoRewardWrapper>( PredefinedKeys.videoRewardManager)).ifPresent((v) { });
这个方案最大的问题是需要手敲具体的类和key, 从一个黑盒里面拿东西感觉总是不太好
期望的形态 注册成功的依赖都直接是Provider
的成员, 现在的形式如果不是自己写的话很可能就不知道是否有这个东西
调查的一些方案 Injector , 使用起来效果和SharedStateStore
效果差不多, 只是这个的key是可选参数, 这个方案的好处就是简单, 但是因为和已有方案基本一致, 再引入这个依赖意思不大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 final injector = Injector.appInstance;injector.registerDependency<Engine>(() => Engine()); injector.registerDependency<Car>(() { final engine = injector.get <Engine>(); return CarImpl(engine: engine); }); injector.register(CustomFactory(() => Engine())); injector.registerSingleton<Database>(() => TikkrDatabase()); database = injector.get <Database>(); customerCar = injector.get <Car>();
Qinject 可以达到需求的目标, 它通过annotation
来进行必要的标记说明, 然后通过builder runner根据之前的指示生成具体的代码. 这个库比较高级, 好多参数都能通过标记来解决, 有种Spring DI
的感觉. 可是每次改代码都得重新生成一下代码, 感觉又没必要这么重. 同时这种方案如何处理潜在的循环依赖/依赖初始化顺序问题也没细看. 这个方案备选
最终选定的方案 基于之前调研的内容, 最后决定直接沿用SharedStateStore
, 然后加extension
. 这样既没有增加很多复杂度, 又达成了需求的目标; 但弊端是声明与实现分离了, 同时也没有隐藏填充的细节(Qinject是生成的所以也算隐藏了细节), 这就是这个方案所必须承受的代价了.
1 2 3 4 5 6 7 8 extension Privider on SharedStateStore { AdManager? get adManager { final m = get <Admanager>('ad_manager_key' ).orNull; return m; } }
部分实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import 'dart:async' ;import 'dart:collection' ;import 'package:quiver/core.dart' ;import 'package:tuple/tuple.dart' ;class SharedStateStore { static final SharedStateStore _singleton = SharedStateStore._internal(); final Map <String , dynamic > _store = <String , dynamic >{}; late StreamController<Tuple2<String , dynamic >> _streamController; factory SharedStateStore() { return _singleton; } SharedStateStore._internal() { _streamController = StreamController.broadcast(sync : false ); } void set <T>(String key, T value, {bool withNotify = true }) { _store[key] = value; if (withNotify) { _streamController.add(Tuple2<String , dynamic >(key, value)); } } Optional<T> get <T>(String key) { final obj = _store[key]; if (obj == null || obj is T) { return Optional.fromNullable(_store[key]); } throw TypeError(); } void invalid(String key) { _store.remove(key); _streamController.add(Tuple2<String , dynamic >(key, null )); } void clear() { _store.clear(); } Stream<Optional<T>> onKeyChange<T>(String key) { return _streamController.stream .where((e) => e.item1 == key) .map((e) => Optional.fromNullable(e.item2)); } Map <String , dynamic > get store => UnmodifiableMapView(_store); }
此模块已经发布在pub