3

I have something like this...

define(['ClassA', 'ClassB', 'ClassC'], 
  function(ClassA, ClassB, ClassC) 
  {
    return {
      build: function(className) {
        var obj;
        switch(className)
        {
            case 'ClassA': obj = new ClassA(); break;
            case 'ClassB': obj = new ClassB(); break;
            case 'ClassC': obj = new ClassC(); break;
        }
        return obj;
    }
  }
}

This seems ok but is there a better way to write it? I tried replacing switch to

return new arguments[className]();    // doesn't work

The closest I can get to is to use a map:

var classes = {
    ClassA: ClassA,
    ClassB: ClassB,
    ClassC: ClassC
}
return new classes[className]();

Is there a better way?

1
  • My vote is for the map solution. Minimal code, and it's explicit. Commented Oct 18, 2012 at 22:53

2 Answers 2

3

There's really no problem with your object there.
It's fast, efficient and easy to follow.
The only suggestion I'd have is to create a var to hold the value, or to test more-explicitly if className is a suitable string, and is in fact in your list:

Either:

var construct = classes[className];
if (construct) { return new construct(); }
else { /* handle the case where the class doesn't exist */ }

Or:

return classes[className] && (new classes[className]()) || null;

The second checks for classes[className] and should return a new instance if it exists (JS returns the value on the very right of AND)...
OR it will return null.

Maybe null isn't what you want.
But the point is that you should be prepared to handle somebody passing: "Bob" to your factory, despite the fact that there is no Bob class.

Sign up to request clarification or add additional context in comments.

2 Comments

The drawback is that requirejs will load all 3 files ClassA.js, ClassB.js and ClassC.js instead of just the one needed.
@koral You're absolutely right. Of course, whether that's a drawback, or not, depends on a lot of analysis, in terms of how many pages they're co-used on, how large each one is, minified, and the average transmission-time of one large file, versus three smaller ones, which will not be able to use the same socket (because you're using TLS, of course) and thus suffer multiple handshakes... This is not an at-scale, forever kind of object; the complexity and management-overhead should simply be on the same level as the scope of what's being accomplished.
0

Using Function Modules as Factories:

define(function(require){
    var classes = {
        'ClassA' : require('ClassA'),
        'ClassB' : require('ClassB'),
        'ClassC' : require('ClassC')
    };

    return function(className){
        try {
            return new classes[className];
        } catch(error) {
            throw new Error('Unknown className Specified.');
        }
    }
});

1 Comment

Would love to know why you down-voted the suggested solution. In my case this comes from a real implementation when one care to require only the needed dependencies.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.