0

I am working on my first Node.js project and I have come to an OOP problem that I am not sure how solve in Node.js.

I have a module A:

module.exports = A;

function A() {
}
A.prototype.method = function() { return "A";};
//other methods...

and couple other modules (lets say B and C) that implement same "interface" as A.

Now, I have module X:

module.exports = X;

function X(impl) {
  //choose A, B, or C based on value of impl
}

So the question is, how do I implement X in order to be able to do:

var X = require("x");
var impl = new X("A");
impl.method(); //returns "A"

I believe prototype and __proto__ will be involved?

Edit: What I am trying to achieve is load implementation A, B or C, based on some string value (ENV variable) through standartized interface new X() and then access methods of A(B,C...) through that instance of X.

2
  • huh? maybe its your example code but you don't seem to grasp how this works. Or i don't grasp what your trying to accomplish. See my answer for what I think you are trying to do. Commented Mar 7, 2012 at 9:48
  • 1
    X should have a factory method , you should return either new A , new Bor new C from X.create(A_B_or_C). Commented Mar 7, 2012 at 11:54

3 Answers 3

2

I think this is what you're after:

A.js (B.js and C.js are similar, of course):

function A() {}

A.prototype.method = function() {
    return 'A';
};

module.exports = A;

X.js:

var modules = {
    A: require('./A'),
    B: require('./B'),
    C: require('./C')
}

function X(impl) {
    if(impl in modules)
        return new modules[impl];
    else
        throw new Error('Unknown impl: ' + impl);
}

module.exports = X;

Usage:

var foo = new X('A');
foo.method();
// => 'A'
var bar = new X('B');
bar.method()
// => 'B'

An alternative to keeping the modules object in X is to require inside X(impl) and let require throw the error:

function X(impl) {
    return new require('./' + impl);
}
Sign up to request clarification or add additional context in comments.

2 Comments

This is pretty much how I'd do it, too.Another potential improvement, if you want to do your own error handling but don't want to keep an array of the modules (e.g. you plan on adding D, E, F, etc fairly often) would be using node's require.resolve() feature to ensure the requested module exists before actually requiring it, without needing to look it up in your own array of known modules.
I actually found out that the last bit you have got there will NOT work. For some reason unless you change it to function X(impl) { var x = new require('./' + impl); return x; } the foo.method() will throw an error saying the object does not have the method.
1

To call parent constructor you need to actually call/apply it in the context of the new object. See [1].

To inherit methods, you need to clone the prototype from the parent class to the child class. See [2]

// parentclass.js
var ParentClass = function (arg) {
    console.log("Calling ParentClass constructor with " + arg);
};

ParentClass.prototype.method = function (arg) {
    console.log("Calling ParentClass method with " + arg);
};

// childclass.js
var ChildClass = function () {
    console.log("Calling ChildClass constructor");
    // [1]
    ParentClass.apply(this, arguments);
};

// [2]
ChildClass.prototype = Object.create(ParentClass.prototype);

var instance = new ChildClass('some argument');
instance.method('ahahahah');

Is this exactly what you need ?

1 Comment

thanks. Oh I forgot to export var ParentClass = module.exports = ….
0
//x.js
module.exports = function(a) {
   return a;
}

//a.js
modules.exports = function() {
return {method: function() { return "A" } };
}

var X = require("x");

var impl = new X(require("a"));

impl.method(); //returns "A"

is that correct?

2 Comments

Well, sort of. Except I am not able to call impl.method() since it was declared in A's prototype. Also, this won't call constructors for both X and A.
since data isnt strongly typed this should be easy just copy your pass your prototypes as the arguments to x's require then you can return instance of any of those classes

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.