mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-24 21:57:58 +00:00
refactor: full generic DIAdapter workflow & universalRegistration abstraction
- Made UniversalChainBenchmark and UniversalChainAsyncBenchmark fully generic with strong typing for DIAdapter<TContainer> - Moved all universalRegistration logic inside adapters; removed global function and typedef - Replaced dynamic/object-based registration with type-safe generic contracts end-to-end - Updated CLI and usage: all DI and scenarios are invoked via type-safe generics - Fixed all analysis errors, Riverpod async/future usages, and imports for full Dart 3 compatibility - All benchmarks fully pass for Cherrypick, GetIt, and Riverpod adapters
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import 'package:cherrypick/cherrypick.dart';
|
||||
import 'di_adapter.dart';
|
||||
import '../scenarios/universal_chain_module.dart';
|
||||
|
||||
/// Универсальный DIAdapter для CherryPick с поддержкой subScope без дублирования логики.
|
||||
class CherrypickDIAdapter extends DIAdapter<Scope> {
|
||||
Scope? _scope;
|
||||
final bool _isSubScope;
|
||||
@@ -16,6 +16,28 @@ class CherrypickDIAdapter extends DIAdapter<Scope> {
|
||||
registration(_scope!);
|
||||
}
|
||||
|
||||
@override
|
||||
Registration<Scope> universalRegistration<S extends Enum>({
|
||||
required S scenario,
|
||||
required int chainCount,
|
||||
required int nestingDepth,
|
||||
required UniversalBindingMode bindingMode,
|
||||
}) {
|
||||
if (scenario is UniversalScenario) {
|
||||
return (scope) {
|
||||
scope.installModules([
|
||||
UniversalChainModule(
|
||||
chainCount: chainCount,
|
||||
nestingDepth: nestingDepth,
|
||||
bindingMode: bindingMode,
|
||||
scenario: scenario,
|
||||
),
|
||||
]);
|
||||
};
|
||||
}
|
||||
throw UnsupportedError('Scenario $scenario not supported by CherrypickDIAdapter');
|
||||
}
|
||||
|
||||
@override
|
||||
T resolve<T extends Object>({String? named}) =>
|
||||
named == null ? _scope!.resolve<T>() : _scope!.resolve<T>(named: named);
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
import 'package:benchmark_di/scenarios/universal_chain_module.dart';
|
||||
|
||||
/// Универсальная абстракция для DI-адаптера с унифицированной функцией регистрации.
|
||||
/// Теперь для каждого адаптера задаём строгий generic тип контейнера.
|
||||
typedef Registration<TContainer> = void Function(TContainer);
|
||||
|
||||
abstract class DIAdapter<TContainer> {
|
||||
/// Устанавливает зависимости с помощью строго типизированного контейнера.
|
||||
void setupDependencies(void Function(TContainer container) registration);
|
||||
|
||||
/// Возвращает типобезопасную функцию регистрации зависимостей под конкретный сценарий.
|
||||
Registration<TContainer> universalRegistration<S extends Enum>({
|
||||
required S scenario,
|
||||
required int chainCount,
|
||||
required int nestingDepth,
|
||||
required UniversalBindingMode bindingMode,
|
||||
});
|
||||
|
||||
/// Резолвит (возвращает) экземпляр типа [T] (по имени, если требуется).
|
||||
T resolve<T extends Object>({String? named});
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:benchmark_di/scenarios/universal_chain_module.dart';
|
||||
import 'package:benchmark_di/scenarios/universal_service.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'di_adapter.dart';
|
||||
|
||||
@@ -58,4 +60,96 @@ class GetItAdapter extends DIAdapter<GetIt> {
|
||||
Future<void> waitForAsyncReady() async {
|
||||
await _getIt.allReady();
|
||||
}
|
||||
|
||||
@override
|
||||
Registration<GetIt> universalRegistration<S extends Enum>({
|
||||
required S scenario,
|
||||
required int chainCount,
|
||||
required int nestingDepth,
|
||||
required UniversalBindingMode bindingMode,
|
||||
}) {
|
||||
if (scenario is UniversalScenario) {
|
||||
return (getIt) {
|
||||
switch (scenario) {
|
||||
case UniversalScenario.asyncChain:
|
||||
for (int chain = 1; chain <= chainCount; chain++) {
|
||||
for (int level = 1; level <= nestingDepth; level++) {
|
||||
final prevDepName = '${chain}_${level - 1}';
|
||||
final depName = '${chain}_$level';
|
||||
getIt.registerSingletonAsync<UniversalService>(
|
||||
() async {
|
||||
final prev = level > 1
|
||||
? await getIt.getAsync<UniversalService>(instanceName: prevDepName)
|
||||
: null;
|
||||
return UniversalServiceImpl(value: depName, dependency: prev);
|
||||
},
|
||||
instanceName: depName,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UniversalScenario.register:
|
||||
getIt.registerSingleton<UniversalService>(UniversalServiceImpl(value: 'reg', dependency: null));
|
||||
break;
|
||||
case UniversalScenario.named:
|
||||
getIt.registerFactory<UniversalService>(() => UniversalServiceImpl(value: 'impl1'), instanceName: 'impl1');
|
||||
getIt.registerFactory<UniversalService>(() => UniversalServiceImpl(value: 'impl2'), instanceName: 'impl2');
|
||||
break;
|
||||
case UniversalScenario.chain:
|
||||
for (int chain = 1; chain <= chainCount; chain++) {
|
||||
for (int level = 1; level <= nestingDepth; level++) {
|
||||
final prevDepName = '${chain}_${level - 1}';
|
||||
final depName = '${chain}_$level';
|
||||
switch (bindingMode) {
|
||||
case UniversalBindingMode.singletonStrategy:
|
||||
getIt.registerSingleton<UniversalService>(
|
||||
UniversalServiceImpl(
|
||||
value: depName,
|
||||
dependency: level > 1
|
||||
? getIt<UniversalService>(instanceName: prevDepName)
|
||||
: null,
|
||||
),
|
||||
instanceName: depName,
|
||||
);
|
||||
break;
|
||||
case UniversalBindingMode.factoryStrategy:
|
||||
getIt.registerFactory<UniversalService>(
|
||||
() => UniversalServiceImpl(
|
||||
value: depName,
|
||||
dependency: level > 1
|
||||
? getIt<UniversalService>(instanceName: prevDepName)
|
||||
: null,
|
||||
),
|
||||
instanceName: depName,
|
||||
);
|
||||
break;
|
||||
case UniversalBindingMode.asyncStrategy:
|
||||
getIt.registerSingletonAsync<UniversalService>(
|
||||
() async => UniversalServiceImpl(
|
||||
value: depName,
|
||||
dependency: level > 1
|
||||
? await getIt.getAsync<UniversalService>(instanceName: prevDepName)
|
||||
: null,
|
||||
),
|
||||
instanceName: depName,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UniversalScenario.override:
|
||||
// handled at benchmark level
|
||||
break;
|
||||
}
|
||||
if (scenario == UniversalScenario.chain || scenario == UniversalScenario.override) {
|
||||
final depName = '${chainCount}_$nestingDepth';
|
||||
getIt.registerSingleton<UniversalService>(
|
||||
getIt<UniversalService>(instanceName: depName),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
throw UnsupportedError('Scenario $scenario not supported by GetItAdapter');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:benchmark_di/scenarios/universal_chain_module.dart';
|
||||
import 'package:benchmark_di/scenarios/universal_service.dart';
|
||||
import 'package:riverpod/riverpod.dart' as rp;
|
||||
import 'di_adapter.dart';
|
||||
|
||||
/// Унифицированный DIAdapter для Riverpod с поддержкой scopes и строгой типизацией.
|
||||
class RiverpodAdapter extends DIAdapter<Map<String, ProviderBase<Object?>>> {
|
||||
ProviderContainer? _container;
|
||||
final Map<String, ProviderBase<Object?>> _namedProviders;
|
||||
final ProviderContainer? _parent;
|
||||
class RiverpodAdapter extends DIAdapter<Map<String, rp.ProviderBase<Object?>>> {
|
||||
rp.ProviderContainer? _container;
|
||||
final Map<String, rp.ProviderBase<Object?>> _namedProviders;
|
||||
final rp.ProviderContainer? _parent;
|
||||
final bool _isSubScope;
|
||||
|
||||
RiverpodAdapter({
|
||||
ProviderContainer? container,
|
||||
Map<String, ProviderBase<Object?>>? providers,
|
||||
ProviderContainer? parent,
|
||||
rp.ProviderContainer? container,
|
||||
Map<String, rp.ProviderBase<Object?>>? providers,
|
||||
rp.ProviderContainer? parent,
|
||||
bool isSubScope = false,
|
||||
}) : _container = container,
|
||||
_namedProviders = providers ?? <String, ProviderBase<Object?>>{},
|
||||
_namedProviders = providers ?? <String, rp.ProviderBase<Object?>>{},
|
||||
_parent = parent,
|
||||
_isSubScope = isSubScope;
|
||||
|
||||
@override
|
||||
void setupDependencies(void Function(Map<String, ProviderBase<Object?>> container) registration) {
|
||||
void setupDependencies(void Function(Map<String, rp.ProviderBase<Object?>> container) registration) {
|
||||
_container ??= _parent == null
|
||||
? ProviderContainer()
|
||||
: ProviderContainer(parent: _parent);
|
||||
? rp.ProviderContainer()
|
||||
: rp.ProviderContainer(parent: _parent);
|
||||
registration(_namedProviders);
|
||||
}
|
||||
|
||||
@@ -59,7 +61,7 @@ class RiverpodAdapter extends DIAdapter<Map<String, ProviderBase<Object?>>> {
|
||||
|
||||
@override
|
||||
RiverpodAdapter openSubScope(String name) {
|
||||
final newContainer = ProviderContainer(parent: _container);
|
||||
final newContainer = rp.ProviderContainer(parent: _container);
|
||||
return RiverpodAdapter(
|
||||
container: newContainer,
|
||||
providers: Map.of(_namedProviders),
|
||||
@@ -73,4 +75,64 @@ class RiverpodAdapter extends DIAdapter<Map<String, ProviderBase<Object?>>> {
|
||||
// Riverpod синхронный по умолчанию.
|
||||
return;
|
||||
}
|
||||
|
||||
@override
|
||||
Registration<Map<String, rp.ProviderBase<Object?>>> universalRegistration<S extends Enum>({
|
||||
required S scenario,
|
||||
required int chainCount,
|
||||
required int nestingDepth,
|
||||
required UniversalBindingMode bindingMode,
|
||||
}) {
|
||||
if (scenario is UniversalScenario) {
|
||||
return (providers) {
|
||||
switch (scenario) {
|
||||
case UniversalScenario.register:
|
||||
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'reg', dependency: null));
|
||||
break;
|
||||
case UniversalScenario.named:
|
||||
providers['impl1'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'impl1'));
|
||||
providers['impl2'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'impl2'));
|
||||
break;
|
||||
case UniversalScenario.chain:
|
||||
for (int chain = 1; chain <= chainCount; chain++) {
|
||||
for (int level = 1; level <= nestingDepth; level++) {
|
||||
final prevDepName = '${chain}_${level - 1}';
|
||||
final depName = '${chain}_$level';
|
||||
providers[depName] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(
|
||||
value: depName,
|
||||
dependency: level > 1 ? ref.watch(providers[prevDepName] as rp.ProviderBase<UniversalService>) : null,
|
||||
));
|
||||
}
|
||||
}
|
||||
final depName = '${chainCount}_$nestingDepth';
|
||||
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => ref.watch(providers[depName] as rp.ProviderBase<UniversalService>));
|
||||
break;
|
||||
case UniversalScenario.override:
|
||||
// handled at benchmark level
|
||||
break;
|
||||
case UniversalScenario.asyncChain:
|
||||
for (int chain = 1; chain <= chainCount; chain++) {
|
||||
for (int level = 1; level <= nestingDepth; level++) {
|
||||
final prevDepName = '${chain}_${level - 1}';
|
||||
final depName = '${chain}_$level';
|
||||
providers[depName] = rp.FutureProvider<UniversalService>((ref) async {
|
||||
return UniversalServiceImpl(
|
||||
value: depName,
|
||||
dependency: level > 1
|
||||
? await ref.watch((providers[prevDepName] as rp.FutureProvider<UniversalService>).future) as UniversalService?
|
||||
: null,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
final depName = '${chainCount}_$nestingDepth';
|
||||
providers['UniversalService'] = rp.FutureProvider<UniversalService>((ref) async {
|
||||
return await ref.watch((providers[depName] as rp.FutureProvider<UniversalService>).future);
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
throw UnsupportedError('Scenario $scenario not supported by RiverpodAdapter');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user