electrolyte
electrolyte copied to clipboard
Constructor passed an object with dependencies instead of as parameters
I was looking to add the feature in myself, but I'm not very clear on your code base and not sure how it would fit in.
As an alternative to passing in dependencies to a constructor as each dependency being a parameter, and thus possibly creating a very unwieldy constructor signature, it would be nice if the dependencies could be passed in as an object.
As an example:
exports = module.exports = function(deps) {
...
};
exports['@requireObj'] = [ 'foo', 'bar' ];
And then deps would look like:
{
foo: {},
bar: {} // or whatever the instance is supposed to be
}
I decided to look at this again. It seems like it would be a fairly trivial change if you're up for API breakage. Simply adjust Component.prototype.create to:
Component.prototype.create = function(container) {
debug('create %s', this.id);
var source = container._sources[this._sid];
var loaded = this.loaded;
if (!this.loaded) {
var deps = this.dependencies
, args = {};
for (var i = 0, len = deps.length; i < len; ++i) {
var inst = container.create(deps[i], this);
if (source) {
if (typeof source.fn.scope == 'function') {
inst = source.fn.scope(deps[i], inst, { prefix: source.prefix, options: source.options });
}
}
args[deps[i]] = inst;
}
}
var i = this.instantiate.apply(this, [args]);
if (!loaded && container._expose) {
container._expose.call(container, this.id, i, this.singleton)
}
return i;
}
Note that args is no longer an array, but an object. As the dependencies are instantiated, they're added to the args object as the value of a property named after the dependency name.
As I am writing this post, I have realized that dependency names with a path could be a problem. I'm not sure how to handle that scenario.
You'd also run into sticky issues with dependencies like "users/db" and "music/db" where there are two objects named the same thing (with different paths).
Honestly, I'm not really a fan of the object idea. It seems like it'll have a lot of edge cases that'll get messy, and if your constructor signature is that big to make this a problem, you probably have a class that is too complicated itself.
I agree. I wasn't really trying to solve a constructor with too many dependencies problem. More this pattern:
var foo;
var bar;
// implementation
exports = module.exports = function($foo, $bar) {
foo = $foo;
bar = $bar;
return something;
}
exports['@require'] = [ 'foo', 'bar' ];
The overly long constructor being resolved was just a nice side effect.
However, I don't see how "users/db" and "music/db" would conflict. You'd be passing in an object like:
{
"users/db": {},
"music/db": {}
}
The ugliness there is in accessing those fields.
This is an example of how I deal with it:
class Foo {
constructor(args) {
this._settings = args.settings;
this._bar = args.bar
}
}
module.exports['@require'] = [
'config/settings',
'components/bar'
]
module.exports = (settings, bar) => {
return new Foo({
settings: settings,
bar: bar
});
};