simple_service_container 1.0.0-dev.2 copy "simple_service_container: ^1.0.0-dev.2" to clipboard
simple_service_container: ^1.0.0-dev.2 copied to clipboard

Provides a service container and utilities for simple, non-lazy IOC.

Provides a service container and utilities for simple, non-lazy IOC.

Set-up #

Just add following dependency to your pubspec.yaml:

dependencies:
  simple_service_container: ^1.0.0

Usage #

We can create a ServiceContainer.

final groceryServices = ServiceContainer();

Then register services using the register method.

groceryServices.register<String>('Global Grocery Store');

Doing setup logic and service registration via extensions is recommended for organization and to declutter the application root.

await groceryServices.setupFridge();
await groceryServices.setupBakery();
await groceryServices.setupProduce();
await groceryServices.setupGrocery();

If we attempt to register a service that has already been registered in the container then we get an error immediately.

// This will throw an ArgumentError
groceryServices.register(
  Bakery(breads: ['Sourdough', 'Cheesy Rolls', 'Banana Bread']),
);

We can also create sub-containers that inherit services from their parent

final subContainer = ServiceContainer(groceryServices);

Alternatively we can make a specific type of sub-container as a sub-type of ServiceContainer. This allows us to organize the logic for overriding services.

class LocalGroceryServiceContainer extends ServiceContainer {
  LocalGroceryServiceContainer._new(super.parent);

  static Future<LocalGroceryServiceContainer> create(
    ServiceContainer parent,
  ) async {
    final services = LocalGroceryServiceContainer._new(parent);

    // We can override the registration of services inherited from a parent
    // container
    services.register<String>('Local Grocery Store');

    final localBakery = services.register(
      Bakery(breads: ['Sourdough', 'Cheesy Rolls', 'Banana Bread']),
    );

    // We should also override the registration of dependent services since they
    // don't automatically rebuild
    services.register(
      GroceryStore(
        produce: services.get<ProduceAisle>(),
        fridge: services.get<Fridge>(),
        bakery: localBakery,
      ),
    );

    // We can also flatten remaining non-overridden services from the parent
    // container into the sub-container before use to ensure best performance
    // and prevent further overriding.
    services.flatten();

    return services;
  }
}

The above also provides us with a different type that can be registered to the parent container, meaning we can inject sub containers via their parent. This is especially useful for pulling as much initialization logic to the top-level of the application as possible, allowing errors to be evident as soon as the app runs for faster and more reliable debugging.

final localGroceryServices = await LocalGroceryServices.create(
groceryServices,
);

groceryServices.register(localGroceryServices);

Then in our app we can pass the services downwards, get services out of the container, and use them.

void doGroceryAppThings(ServiceContainer services) {
  // We can get services out of the container by using get if we're sure they
  // are registered (if they are not this will throw an error)
  final store = services.get<GroceryStore>();
  printGroceries(store);

  // If we aren't sure if a service has been registered we can use tryGet,
  // which will return null if the service is not registered.
  final maybeString = services.tryGet<String>();
  if (maybeString != null) {
    print(maybeString);
  }

  // Any sub-typed sub-containers we registered, we can get out and pass along
  // to the parts of our app that should use those services
  final localGroceryServices = services.get<LocalGroceryServices>();
  doLocalGroceryThings(localGroceryServices);
}

void doLocalGroceryThings(ServiceContainer services) {
  printGroceries(services.get<GroceryStore>());
}

void printGroceries(GroceryStore store) {
  store.bakery.breads.forEach(print);
  store.fridge.meats.forEach(print);
  store.produce.fruit.forEach(print);
  store.produce.veg.forEach(print);
}

Extensions #

simple_service_container can be used on its own, but the following packages are designed specifically to extend its functionality and improve its ease-of-use in particular use cases:

0
likes
160
points
1
downloads

Publisher

verified publisherliamrobinson.co.uk

Weekly Downloads

Provides a service container and utilities for simple, non-lazy IOC.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

meta

More

Packages that depend on simple_service_container