Dependency Injection Container in less than 50 lines of code.
desire()
is to components as require()
is to modules.
I'd think of desire as a way of solving the dependency problem rather than calling it a library, and that this library is a reference implementation of a desire container; it contained no magic, but small, straightforward code.
desire is unlicensed. It's public domain. You can use it for anything you want.
To define a component that desires other components, create a component factory.
var App = function(desire) {
var ui = desire('ui')
var version = desire('version')
return {
run: function() {
console.log('application version ' + version)
ui.show()
console.log('ui is visible')
}
}
}
Other components do the same:
var UI = function(desire) {
return {
show: function() {
console.log('display ui')
}
}
}
To put them all together, create a container, register the component factories, and then call desire("component name").
var Desire = require('./.')
var desire = new Desire()
desire.register({
app: App,
ui: UI,
version: Desire.value('1.0.0')
})
var app = desire('app')
app.run()
desire.register(object)
takes an object and adds each property to
the container's registry.
The property's name is the component's name and the property's value is the component factory function (see above examples).
desire(componentName)
will look up a component given by componentName
in the container's cache.
If the component is not in the cache,
the component factory will be invoked,
and the returned component will be put into the container's cache.
An error is thrown when the component factory with the requested name is not in the registry.
This desire
function is the same function that is passed to the
component factory, so each component can desire other components.
Again, see the above examples, or read the source code.
You can manually inject dependencies too.
Because a component factory is just a function that desires other components,
we can create a Desire()
and pass it to the factory ourselves.
var FakeUI = function(desire) {
return {
show: function() {
console.log('this is a fake ui')
}
}
}
var app2 = App(new Desire({ ui: FakeUI, version: Desire.value('mock') }))
app2.run()
You can call desire.clone()
to create a copy of the container.
Only the registry will be copied. The cache will not be copied.
Sometimes you want to have a component that have sub-components, but you want them to be isolated from the rest of the world.
That's when you can create a child container.
var child = new Desire(parent)
It behaves like normal containers, but when you look up a component that's not in the child's registry, it will look up in the parent's registry too.
Above was all that desire does. The rest is up to you.
In this section I will show you some usage patterns.
I usually write a module to represent a component.
In this example you will see the analogy between require
and desire
.
Use require
to request another module, and use desire
to request another
component.
var It = require('it.js')
module.exports = function RoomService(desire) {
var database = desire('database')
return { ... }
}
Usage:
desire.register({ rooms: require('./components/room_service') })
desire
manages just the dependencies for you.
You have to manage configrations yourself...
One way to do it is make a "component factory factory".
module.exports = function(config) {
return function RoomService(desire) {
var database = desire('database')
return { ... }
}
}
desire.register({ rooms: require('./components/room_service')({ ... }) })
Another way is to use Function.prototype.bind
to bing the configuration to this
.
module.exports = function RoomService(desire) {
var config = this
var database = desire('database')
return { ... }
}
desire.register({ rooms: require('./components/room_service').bind({ ... }) })
Yet another way is to treat configuration as a dependency.
module.exports = function Database(desire) {
var config = desire('database.config')
return { ... }
}
desire.register({
'database': require('./components/database'),
'database.config': Desire.value({ host: 'localhost', ... })
})