I don't have a lot of experience writing libraries and just recently started thinking a lot about structure and patterns.
I wrote a tiny module manager based on the facade and mediator design patterns and very vaguely based on require.js / AMD and libraries using facade+mediator patterns like jQuery.
My goal is not only to decouple but to provide a minimal, self-descriptive mediator function as an entrance point into modules serving as a kind of tutorial.
So if everything works out inspecting a module via console.log()
, it only shows the exposed mediator function and hopefully gives the required information needed to use the module without looking up in the documentation most of the time
Here is an example module featuring all structural components:
imports(["module1","module2"],function privateModuleConstructor(moduleOne,moduleTwo){
var privateVar = "hidden and can only be accessed through the closure";
return exports(function longDescriptiveMediatorName(){
var a = arguments,
l = a.length;
c = a.callee;
/* ...exposed part of the facade... */
if(l===0) {return privateMethod()};
if(typeof a[0] === "string") {return privateVar+a[0]};
if(a[0] instanceof Array) {return privateMethod.apply(c,a[0])}
},[module1,module2,publicMethod],"shortAlias");
function privateMethod(){
return privateVar.replace(/hidden/,"now revealed");
}
function publicMethod(){
return "exposing methods without mediator increases coupling but is possible"
}
})
How intuitive does this feel to you? Even without seeing the exact source of imports
and exports
, does this give you the information you would need to write a module yourself?
edit: After using the pattern for a month it turned out to be rather tedious most of the time. Some modules just can't be reasonably decoupled this way, so it's far from being the magic formula solution that solves all my problems. But it did work out very well for some modules.
I ended up just not using the mediator function when starting out to write a new module, simply use the module and then pay attention and decouple when I ended up actually using the module in many different places and saw an opportunity to reduce the complexity of my use cases.
1 Answer 1
Odd question,
arguments.callee
is considered obsolete, it's use will trigger an error in strict mode- On top you use
moduleOne
, but you passmodule1
in the array in yourexports
call - You did not provide the source for
exports
- You have both missing & unnecessary semicolons ( jshint.com )
This
var a = arguments, l = a.length; c = a.callee;
should be
var a = arguments, l = a.length, //<- Comma here c = a.callee;
Traditionally the private things go on top, with a return/export at the bottom, still I like your way better
I'm assuming your exposed part of the facade is just a show case of what you can do and you will not actually decide which function to call based on parameter count and type.
All in all, I find this introduces complexity while not providing very much in return. Personally, I would hold off on modules until I really need them. And then, use require.js.
-
\$\begingroup\$ Thanks for the detailed feedback! I didn't know about the arguments.callee deprecation. I'm going to edit in my experiences using / tweaking this pattern for a month into the question. \$\endgroup\$Winchestro– Winchestro2014年07月15日 08:01:15 +00:00Commented Jul 15, 2014 at 8:01
privateMethod.apply(null,a[0])
rather thanprivateMethod(a[0])
? Passingnull
as a context is pointless, IMO. \$\endgroup\$.apply
and.call
or()
\$\endgroup\$