Module multiple_containers
Aedi, a dependency injection library.
Aedi is a dependency injection library. It does provide a set of containers that do IoC, and an interface to configure application components (structs, objects, etc.)
Aim
The aim of library is to provide a dependency injection solution that is feature rich, easy to use, easy to learn, and easy to extend up to your needs.
In most simple applications, a single container, like singleton or prototype one might be enough, for using. Having a set of singletons constructed on behalf of a developer is convenient, yet there are occurences a single container is not enough. For example when, a set of components rely on a particular dependency, and more specifically, the dependency they rely upon, should not be shared across reliant components. In another case, a set of components are stored in a database, in serialized form, and they are used as dependencies for other components from application.
In such cases use of a single container like singleton or prototype is not enough, since one set of components should be created by using normal frameworks means, and another set needs to be fetched from a database, or should not be shared to all dependent components. To solve this problem, AEDI framework, allows container to be joined and used together, for creation of components. A component in such a joint container, having a dependency on a prototype component, will have it’s requirement fullfilled without a problem.
Using as an example car simulation app, the company decided to add a set ”tires” to simulated cars. For a particular car, each tire installed in it has same properties as other installed in same car. Registering 4 times same tire is not cost effective. Instead of it, it is better to register component into a prototype container and use component to supply 4 instances of a tire to a particular car. Example below shows how two or more containers can be joined together, configured with components, and used to instantiate required components.
auto container = aggregate( // Create a joint container hosting other two containers
singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity
prototype(), "prototype" // Create prototype container, and store it in joint container by "prototype" identity
);
with (container .configure("singleton")) { // Configure singleton container
// ...
register!Car
.autowire
.autowire!"color"
.set!"frontLeft"(lref!Tire)
.set!"frontRight"(lref!Tire)
.set!"backLeft"(lref!Tire)
.set!"backRight"(lref!Tire);
}
with (container .configure("prototype")) { // Configure prototype container
register!Tire // Registering Tire into "prototype" container used by aggregate container
.set!"size"(17)
.set!"pressure"(3.0)
.set!"vendor"("divine tire");
}
//...
To join one or more containers together, an aggregate container must be created that will host
both of them under the hood. Once aggregate container has all of joint containers registered in it,
the process of registering components takes place.
To register components in joint container, pass the identity of subcontainer (container in joint container)
to configure
as an argument, and register components for selected subcontainer.
The configure
function applied to joint container in with ()
statement
creates a configuration context, that stores the container where components are stored, and
container from which dependencies for those components should be fetched.
In case of joint container, and singleton subcontainer, singleton subcontainer acts as storage while
joint container is used as source for dependencies of registered components.
In the result, the car simulator will be able to use a car, that has 4 different instances of a tire. Output below shows the constructed car by joint containers.
Uuh, what a nice car, Electric car with following specs:
Size: Size(200, 150, 300)
Color: Color(0, 0, 0)
Engine: app .ElectricEngine
Tire front left: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C31180
Tire front right: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C311C0
Tire back left: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C31200
Tire back right: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C31240
Notice that each tire is a different object, hence everything is working as we expected!
Try this example, modify it, play with it to understand how compositing can help in designing your application.
Functions
Name | Description |
---|---|
drive(car, name)
|
|
main()
|
Interfaces
Name | Description |
---|---|
Engine
|
Interface for engines. |
Classes
Name | Description |
---|---|
Car
|
A class representing a car. |
CarManufacturer
|
A manufacturer of cars. |
DieselEngine
|
A concrete implementation of Engine that uses diesel for propelling. |
ElectricEngine
|
A concrete implementation of Engine that uses electricity for propelling. |
GasolineEngine
|
A concrete implementation of Engine that uses gasoline for propelling. |
Tire
|
Tire, what it can represent else? |
Structs
Name | Description |
---|---|
Color
|
A struct that should be managed by container. |
Size
|
Size of a car. |