A functional DI container.
const scope:Scope = new Scope();
scope.register(User); // configures User singleton
scope.getValue(User); // creates singleton User instance
scope.getValue(User); // returns the same User instance
- Managed singletons
- Scope inheritance
- Inline and external configuration options
- Constructor and property injection
- Flexible construction and injection mechanics
scope.register(IVehicle, Car); // interface singleton
scope.getValue(IVehicle); // returns a Car instance
const childScope:Scope = new Scope();
childScope.parent = scope; // sets scope inheritance
childScope.getValue(IVehicle); // returns inherited engine
childScope.register(IVehicle, Bicycle); // overrides to local singleton
childScope.getValue(IVehicle); // returns local singleton
childScope.unregister(IVehicle); // unregisters local singleton
childScope.getValue(IVehicle); // returns inherited engine
Scope
is an implementation that conforms to the following specification.
- "value" is any legal ActionScript value or reference.
- "identity" is any legal ActionScript value or reference.
- "resolver" is any function that takes an
identity
and returns avalue
. - "provider" is any
value
or function that returns avalue
when invoked.
The spec defines two concepts:
- Resolver Functions
- Provider Functions and Values
This is enough to build a moderately elaborate DI container.
A resolver is any function that takes an identity and returns a value:
function(id:Object):Object {
// ...
return object;
}
A resolver should throw an exception if it can not provide a value for a given identity.
A provider can be any legal ActionScript value (including null
and undefined
):
var urlProvider:String = "http://example.com/api"
A provider can be function that returns a value when invoked:
function():String { return "http://example.com/api" }
A provider can optionally accept a resolver as a parameter:
function(resolve:Function):Service {
return new Service(resolve("serviceURL"))
}
Pilots fly aeroplanes, they don't have to know how to build them.
DI frameworks separate operational concerns from constructional concerns.
DI containers are just object factories.
A good DI container is a flexible and easily configurable object factory.