build method
Builds and returns an instance of type T
from the registered factories,
initializing all types that implements IInitializable.
Factories are ordered in a topological order, ensuring that dependencies are resolved before the instance is created.
T
: The type of the instance to build.
Throws an StateError if no factory is registered for the type T
or
if a cyclic dependency is detected.
Implementation
Future<Dependencies> build() async {
final graph = <Type, List<Type>>{};
final inDegrees = <Type, int>{};
for (final dep in _dependencies) {
graph[dep.type] = [];
inDegrees[dep.type] = 0;
}
for (final dep in _dependencies) {
for (final dependency in dep.dependsOn) {
if (graph.containsKey(dependency) == false) {
throw StateError(
"Dependency '$dependency' not found for '${dep.type}'.",
);
}
graph[dependency]!.add(dep.type);
inDegrees[dep.type] = (inDegrees[dep.type] ?? 0) + 1;
}
}
final queue = Queue<Type>();
final sorted = <Dependency<Object>>[];
for (final entry in inDegrees.entries) {
if (entry.value == 0) {
queue.add(entry.key);
}
}
while (queue.isNotEmpty) {
final current = queue.removeFirst();
final currentDep = _dependencies.firstWhere((dep) => dep.type == current);
sorted.add(currentDep);
for (final neighbor in graph[current]!) {
inDegrees[neighbor] = inDegrees[neighbor]! - 1;
if (inDegrees[neighbor] == 0) {
queue.add(neighbor);
}
}
}
if (sorted.length != _dependencies.length) {
throw StateError("Cyclic dependency detected!");
}
for (final dependency in sorted) {
log("Instantiating", name: "${dependency.type}");
final instance = dependency.factory(this);
if (instance is IInitializable) {
log("Initializing", name: "${dependency.type}");
await instance.initialize();
}
_instances[dependency.type] = MapEntry(this, instance);
}
return this;
}