Add autowiring to array to tutorial

This commit is contained in:
Mike Bierlee 2015-07-04 14:36:41 +02:00
parent 9d5b4e97a7
commit 5c9a623ef6

View file

@ -1,113 +1,130 @@
Poodinis Tutorial Poodinis Tutorial
================= =================
This tutorial will give you an overview of all functionality offered by Poodinis and how to use them. This tutorial will give you an overview of all functionality offered by Poodinis and how to use them.
The container The container
------------- -------------
To register a class, a new dependency container must be instantiated: To register a class, a new dependency container must be instantiated:
```d ```d
// Register a private container // Register a private container
auto dependencies = new DependencyContainer(); auto dependencies = new DependencyContainer();
// Or use the singleton container // Or use the singleton container
dependencies = DependencyContainer.getInstance(); dependencies = DependencyContainer.getInstance();
``` ```
###Registering dependencies ###Registering dependencies
To make dependencies available, they have to be registered: To make dependencies available, they have to be registered:
```d ```d
// Register concrete class // Register concrete class
dependencies.register!ExampleClass; dependencies.register!ExampleClass;
// Register by interface // Register by interface
dependencies.register!(ExampleInterface, ExampleClass); dependencies.register!(ExampleInterface, ExampleClass);
``` ```
In the above example, dependencies on the concrete class and interface will resolve an instance of class ExampleClass. Registering a class by interface does not automatically register by concrete type. In the above example, dependencies on the concrete class and interface will resolve an instance of class ExampleClass. Registering a class by interface does not automatically register by concrete type.
Resolving dependencies Resolving dependencies
---------------------- ----------------------
To manually resolve a dependency, all you have to do is resolve the dependency's type using the container in which it is registered: To manually resolve a dependency, all you have to do is resolve the dependency's type using the container in which it is registered:
```d ```d
auto exampleClassInstance = dependencies.resolve!ExampleClass; auto exampleClassInstance = dependencies.resolve!ExampleClass;
``` ```
If the class is registered by interface and not by concrete type, you cannot resolve the class by concrete type. Registration of both a concrete type and interface type will resolve different registrations, returning different instances: If the class is registered by interface and not by concrete type, you cannot resolve the class by concrete type. Registration of both a concrete type and interface type will resolve different registrations, returning different instances:
```d ```d
auto exampleClassInstance = dependencies.resolve!ExampleClass; auto exampleClassInstance = dependencies.resolve!ExampleClass;
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface; auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
assert(exampleClassInstance !is exampleClassInstance2); assert(exampleClassInstance !is exampleClassInstance2);
``` ```
You can solve this by adding the ADD_CONCRETE_TYPE_REGISTRATION option when registering: You can solve this by adding the ADD_CONCRETE_TYPE_REGISTRATION option when registering:
```d ```d
dependencies.register!(ExampleInterface, ExampleClass)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION); dependencies.register!(ExampleInterface, ExampleClass)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION);
auto exampleClassInstance = dependencies.resolve!ExampleClass; auto exampleClassInstance = dependencies.resolve!ExampleClass;
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface; auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
assert(exampleClassInstance is exampleClassInstance2); assert(exampleClassInstance is exampleClassInstance2);
``` ```
Dependency scopes Dependency scopes
----------------- -----------------
With dependency scopes, you can control how a dependency is resolved. The scope determines which instance is returned, be it the same each time or a new one. The following scopes are available: With dependency scopes, you can control how a dependency is resolved. The scope determines which instance is returned, be it the same each time or a new one. The following scopes are available:
* Resolve a dependency using a single instance (default): * Resolve a dependency using a single instance (default):
```d ```d
dependencies.register!(ExampleClass).singleInstance(); dependencies.register!(ExampleClass).singleInstance();
``` ```
* Resolve a dependency with a new instance each time it is resolved: * Resolve a dependency with a new instance each time it is resolved:
```d ```d
dependencies.register!(ExampleClass).newInstance(); dependencies.register!(ExampleClass).newInstance();
``` ```
* Resolve a dependency using a pre-existing instance * Resolve a dependency using a pre-existing instance
```d ```d
auto preExistingInstance = new ExampleClass(); auto preExistingInstance = new ExampleClass();
dependencies.register!(ExampleClass).existingInstance(preExistingInstance); dependencies.register!(ExampleClass).existingInstance(preExistingInstance);
``` ```
Autowiring Autowiring
---------- ----------
The real value of any dependency injection framework comes from its ability to autowire dependencies. Poodinis supports autowiring by simply applying the **@Autowire** UDA to a member of a class: The real value of any dependency injection framework comes from its ability to autowire dependencies. Poodinis supports autowiring by simply applying the **@Autowire** UDA to a member of a class:
```d ```d
class ExampleClassA {} class ExampleClassA {}
class ExampleClassB { class ExampleClassB {
@Autowire @Autowire
public ExampleClassA dependency; public ExampleClassA dependency;
} }
dependencies.register!ExampleClassA; dependencies.register!ExampleClassA;
auto exampleInstance = new ExampleClassB(); auto exampleInstance = new ExampleClassB();
dependencies.autowire(exampleInstance); dependencies.autowire(exampleInstance);
assert(exampleInstance.dependency !is null); assert(exampleInstance.dependency !is null);
``` ```
At the moment, it is only possible to autowire public members or properties. At the moment, it is only possible to autowire public members or properties.
Dependencies are automatically autowired when a class is resolved. So when you register ExampleClassB, its member, *dependency*, is automatically autowired: Dependencies are automatically autowired when a class is resolved. So when you register ExampleClassB, its member, *dependency*, is automatically autowired:
```d ```d
dependencies.register!ExampleClassA; dependencies.register!ExampleClassA;
dependencies.register!ExampleClassB; dependencies.register!ExampleClassB;
auto instance = dependencies.resolve!ExampleClassB; auto instance = dependencies.resolve!ExampleClassB;
assert(instance.dependency !is null); assert(instance.dependency !is null);
``` ```
If an interface is to be autowired, you must register a concrete class by interface. Any class registered by concrete type can only be injected when a dependency on a concrete type is autowired. If an interface is to be autowired, you must register a concrete class by interface. Any class registered by concrete type can only be injected when a dependency on a concrete type is autowired.
Circular dependencies Circular dependencies
--------------------- ---------------------
Poodinis can autowire circular dependencies when they are registered with singleInstance or existingInstance registration scopes. Circular dependencies in registrations with newInstance scopes will not be autowired, as this would cause an endless loop. Poodinis can autowire circular dependencies when they are registered with singleInstance or existingInstance registration scopes. Circular dependencies in registrations with newInstance scopes will not be autowired, as this would cause an endless loop.
Registering and resolving using qualifiers Registering and resolving using qualifiers
------------------------------------------ ------------------------------------------
You can register multiple concrete types to a super type. When doing so, you will need to specify a qualifier when resolving that type: You can register multiple concrete types to a super type. When doing so, you will need to specify a qualifier when resolving that type:
```d ```d
// Color is an interface, Blue and Red are classes implementing that interface // Color is an interface, Blue and Red are classes implementing that interface
dependencies.register!(Color, Blue); dependencies.register!(Color, Blue);
dependencies.register!(Color, Red); dependencies.register!(Color, Red);
auto blueInstance = dependencies.resolve!(Color, Blue); auto blueInstance = dependencies.resolve!(Color, Blue);
``` ```
If you want to autowire a type registered to multiple concrete types, specify a qualified type as template argument: If you want to autowire a type registered to multiple concrete types, specify a qualified type as template argument:
```d ```d
class BluePaint { class BluePaint {
@Autowire!Blue @Autowire!Blue
public Color color; public Color color;
} }
``` ```
If you registered multiple concrete types to the same supertype and you do not resolve using a qualifier, a ResolveException is thrown stating that there are multiple candidates for the type to be resolved. If you registered multiple concrete types to the same supertype and you do not resolve using a qualifier, a ResolveException is thrown stating that there are multiple candidates for the type to be resolved.
Autowiring all registered instances to an array
-----------------------------------------------
If you have registered multiple concrete types to a super type, you can autowire them all to an array, in which case you can easily operate on them all:
```d
// Color is an interface, Blue and Red are classes implementing that interface
class ColorMixer {
@Autowire
public Color[] colors;
}
dependencies.register!(Color, Blue);
dependencies.register!(Color, Red);
auto mixer = dependencies.resolve!ColorMixer;
```
Member mixer.colors will now contrain instances of Blue and Red. The order of the instances is not guarenteed to be that of the order in which they were registered.