df_di 0.1.0+2 copy "df_di: ^0.1.0+2" to clipboard
df_di: ^0.1.0+2 copied to clipboard

A powerful and versatile dependency injection (DI) system with service classes for easy state management.

DF - DI (Dependency Injection) #

Buy Me A Coffee

Dart & Flutter Packages by DevCetra.com & contributors.

Pub Package MIT License


Summary #

This package offers a powerful and versatile dependency injection system along with service classes for easy state management.

Features #

  • Robust support for FutureOr, facilitating seamless handling of both synchronous and asynchronous dependencies and callbacks.
  • Ability to register dependencies using both “type” and “key”, enabling the management of multiple dependencies of the same type.
  • Supports standard features like factory dependencies and lazy initialization for singleton dependencies.
  • Abstract service classes that integrate effortlessly with your application.
  • Clear and comprehensive documentation for easy understanding.
  • Code snippets for Visual Studio Code here.

For a full feature set, please refer to the API reference.

Quickstart #

Creating a DI instance: #

// Access the global DI instance from anywhere in your app.
di;
DI.global;

// Or create a local DI instance.
final local = DI.newInstance();

Registering Dependencies: #

// Register a dependency under type "int" and defaultKey.
di.register<int>(1);
print(DIKey.defaultKey);

// Register a dependency under type "int" also but with a different key.
di.register(2, key: const DIKey('second'));

// Register a Future.
di.register<double>(Future.value(3.0));

int counter = 0;
di.registerSingleton<int>(() => ++counter), key: const DIKey('singleton-counter')); 
di.registerFactory<int>(() async => ++counter, key: const DIKey('factory-counter')); 

Unregistering Dependencies: #

// Throws an error because there is no dependency registered under type "String".
FutureOr<void> futureOr = di.unregister<String>();

// Unregister all dependencies in the reverse order of their registration, effectively resetting the instance di.
futureOr = di.unregisteAll();

Getting Dependencies: #

// Getting a dependency under type "int" and defaultKey.
FutureOr<void> futureOr = di<int>();
print(futureOr); // prints 1

// Register a dependency under type "int" also but with a different key.
print(di.get<int>(const DIKey('second'))); // prints 2

print(await di.get<double>()); // prints 3.0.

print(await di.getFactory<double>(ey: const DIKey('factory-counter'))); // prints 1.
print(await di.getFactory<double>(ey: const DIKey('factory-counter'))); // prints 2.
print(await di.get<double>(ey: const DIKey('factory-counter'))); // prints 3.
print(await di.get<double>(ey: const DIKey('factory-counter'))); // prints 4.

Creating a new Singleton Service: #

final class FooBarService extends Service {
  // Provide objects that the UI can consume, like ValueNotifiers or Streams, etc.
  ValueListenable<String?> get vFooBar => _vFooBar;
  final _vFooBar = ValueNotifier<String?>(null);

  @override
  FutureOr<void> onInitService() async {
    _vFooBar.value = 'FooBar';
    // Put initialization logic here, like starting Streams. Update the PODs as
    // needed to notify the UI of changes.
  }

  // Always called when unregistering a service.
  @override
  FutureOr<void> onDispose() {
    _vFooBar.dispose();
    // Put cleanup logic here, like disposing resources and canceling Streams.
  }
}

Registering and Using Singleton Services: #

// Register FooBarService as a lazy singleton.
di.registerSingletonService(FooBarService.new);

// Initialize the service, get it, and use it.
final fooBarService1 = await di.get<FooBarService>();
final fooBarService2 = di.get<FooBarService>();
print(fooBarService1 == fooBarService2); // prints true

print(fooBarService.vFooBar.value); // prints "FooBar"

Creating a Sync Service: #

Notice how no onInitService isn't a Future. This means that DI will treat it as sync.

final class SyncServiceExmple extends Service {
  @override
  void onInitService() {}

  // Always called when unregistering a service.
  @override
  void onDispose() {}
}

di.registerSingletonService(SyncServiceExmple.new);

// Use get that returns FutureOr<T> if you don't know what to expect.
print(await di.get<SyncServiceExmple>() is Future); // false

// Use call/getSync/getSyncOrNull if you expect a sync.
print(di<SyncServiceExmple>());
print(di.getSync<SyncServiceExmple>());
print(di.getSyncOrNull<SyncServiceExmple>());

Creating an Async Service: #

Notice how no onInitService is Future. This means that DI will treat it as async.

final class AsyncServiceExample extends Service {
  @override
  Future<void> onInitService() async {
    await Future<void>.delayed(
      const Duration(seconds: 3),
    );
  }

  // Always called when unregistering a service.
  @override
  Future<void> onDispose() async {}
}

di.registerSingletonService(AsyncServiceExample.new);

// Use get that returns FutureOr<T> if you don't know what to expect.
print(await di.get<AsyncServiceExample>() is Future); // true

 // Use getAsync or getAsyncOrNull if you expect an async.
print(await di.getAsync<AsyncServiceExample>());
print(await di.getAsyncOrNull<AsyncServiceExample>());

Getting the State for Debugging: #

// Print the current state of di to understand what's registered.
print(di.registry.state);

// Check if there's a dependency under "int" and DIKey.defaultKey.
print(di.isRegistered<int>());
print(di.registry.getDependency<T>() != null);

// Check how the dependency under "String" and DIKey.defaultKey got initially registered. 
di.registerFactory<String>(() => 'Hello World'); 
print(di<String>()); // prints "Hello World".
print(registrationType<String>()); // prints" FactoryInst<String>"

// Print the registration index of dependency under "int" and DIKey.defaultKey.
print(di.registrationIndex<int>());

Installation #

Use this package as a dependency by adding it to your pubspec.yaml file (see here).


Contributing and Discussions #

This is an open-source project, and we warmly welcome contributions from everyone, regardless of experience level. Whether you're a seasoned developer or just starting out, contributing to this project is a fantastic way to learn, share your knowledge, and make a meaningful impact on the community.

Ways you can contribute: #

  • Buy me a coffee: If you'd like to support the project financially, consider buying me a coffee. Your support helps cover the costs of development and keeps the project growing.
  • Share your ideas: Every perspective matters, and your ideas can spark innovation.
  • Report bugs: Help us identify and fix issues to make the project more robust.
  • Suggest improvements or new features: Your ideas can help shape the future of the project.
  • Help clarify documentation: Good documentation is key to accessibility. You can make it easier for others to get started by improving or expanding our documentation.
  • Write articles: Share your knowledge by writing tutorials, guides, or blog posts about your experiences with the project. It's a great way to contribute and help others learn.

No matter how you choose to contribute, your involvement is greatly appreciated and valued!


Chief Maintainer: #

📧 Email Robert Mollentze at robmllze@gmail.com

Dontations: #

If you're enjoying this package and find it valuable, consider showing your appreciation with a small donation. Every bit helps in supporting future development. You can donate here:

https://www.buymeacoffee.com/robmllze


License #

This project is released under the MIT License. See LICENSE for more information.

1
likes
0
points
502
downloads

Publisher

verified publisherdevcetra.com

Weekly Downloads

A powerful and versatile dependency injection (DI) system with service classes for easy state management.

Repository (GitHub)
View/report issues

Topics

#get-it #dependency-injection #services #state #state-management

Funding

Consider supporting this project:

www.buymeacoffee.com

License

unknown (license)

Dependencies

df_pod, df_type, flutter, meta

More

Packages that depend on df_di