0

I've created a few classes as Controllers for my routes in Node.js and I'd like them to be able to work on a singleton basis (not required, it's an extra)

Main Controller class

class RouteController {

    static getInstance() {
        if (!RouteController.singleton) {
            RouteController.singleton = new RouteController();
        }

        return RouteController.singleton;
    }
}

Now I want to create a route for example viewing posts and I want that class to have the singleton pattern as well, but not cop

PostController class

class PostController extends RouteController {

}

If I do this and check it console.log(RouteController.getInstance() === PostController.getInstance()) it returns true when I want each (sub)class to have their own singleton instance.

How can I do this correctly?

2 Answers 2

2

One simple way would be to see if your singleton property is an instance of this. This will work even if you call RouteController.getInstance() before doing so on any of the derived classes.

class RouteController {
  log() {
    return 'Route';
  }
  static getInstance() {
    if (!(this.singleton instanceof this)) {
      // Only called twice so you can verify it's only initialized
      // once for each class
      console.log('Creating singleton...');
      this.singleton = new this();
    }
    return this.singleton;
  }
}

class PostController extends RouteController {
  log() {
    return 'Post';
  }
}

console.log(RouteController.getInstance().log());
console.log(PostController.getInstance().log());
console.log(RouteController.getInstance().log());
console.log(PostController.getInstance().log());

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

Comments

0

The normal rules of functions apply. Hence you can use this inside the function to refer to the object the method was invoked on (the constructor function itself in this case):

class RouteController {

    static getInstance() {
        if (!this.singleton) {
            this.singleton = new this();
        }

        return this.singleton;
    }
}

However, this will still not work if RouteController.getInstance() is called directly, because then all subclasses inherit a static singleton property, causing the !this.singleton test to fail for each subclass.

There are multiple ways to solve this. One would be to use getOwnProperty instead of accessing it directly:

if (!this.getOwnProperty('singleton')) {

}

9 Comments

I don't think you have access to this in static methods, do you?
@RobM.: Every function has a this value (except arrow functions). If you do RouteController.getInstance(), this refers to RouteController. Normal JavaScript, nothing magical here. After all, static methods are just properties on the function object. (function RouteController() {}; RouteController.getInstance = function() {}).
I should rephrase, I know there will be a this value, I just wasn't aware that it would refer to the class itself in a static method and am a bit surprised by that. Good to know, thanks!
@RobM.: Depends on how the method is called of course, but if you do Foo.bar() as intended, this will refer to Foo.
Like @FelixKling says, this is useable, but no, it does not work. console.log("PostController singleton", PostController.getInstance()); shows the following in the console: PostController singleton RouteController {}
|

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.