DEV Community

Tomas Eglinskas
Tomas Eglinskas

Posted on

Static Factory Methods

As a JavaScript developer without design pattern fundamentals, static factory methods would have made my code cleaner on multiple occasions. If you’re like me - and most people, when you create a class you want to initialise it at some point.

    const Coordinate: Coordinate = new Coordinate(x, y)

    class Coordinate {
      public x: number;
      public y: number;

      constructor(x: number, y: number) {
        this.x = x;
        this.y = y;  
      }
    }
Enter fullscreen mode Exit fullscreen mode

And this behavior is perfectly common - we want to create instances of our classes. But let’s say you want to create a Coordinate which has parameters x & y doubled upon initialization.

The easy and dirty is double it in the constructor

    constructor(x: number, y: number) {
      this.x = 2 * x;
      this.y = 2 * y;
    }
Enter fullscreen mode Exit fullscreen mode

but most of us wouldn’t do this, we would create a method

    class Coordinate {
      ...
      public double() { 
        this.x = this.x * 2;
        this.y = this.y * 2;
      }
    }

    const coordinate = new Coordinate(1, 5).double()
Enter fullscreen mode Exit fullscreen mode

Regular flow and everything is fine. But what if the desired outcome was to create a double Coordinate without the ability to use any methods like double? We don’t want to expose this method for other people to use. What if someone used double 20 times?

We could hide the creation logic and create a static factory method - it would just return a double Coordinate and it would be clear as day. As you can see the constructor is private - the Coordinate creation is encapsulated in the class.

    class Coordinate {
      // ...
      private constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
      }

      static doubledCoordinate(x: number, y: number) { 
        return new Coordinate(x * 2, y * 2)
      }
    }

    const coordinate = Coordinate.doubleCoordinate(1, 5) // and the naming - fancy
Enter fullscreen mode Exit fullscreen mode

Also have in mind, that if you wanted to introduce a side-effect (like a console.log()) in a typical constructor - you would return a new object, by using a static method you are not required to create a new object each time it’s invoked.

This was maybe a trivial example, but the main idea is to hide the implementation from the outside-world - to delegate the construction of an object to the static method, let’s say you have a database connection and you don't want to expose Monitor and how a database is connected and what processing operations it needs to do.

    // some methods are fake

    import Monitor from "//.."

    class Database {  
      private static Monitor = new Monitor()
      private static connection: MongoClient;
      private static regionCount: number = 0;

      static getConnection() {
        if (connection.timedOut() ||
            !connection.established) {
          Monitor.sendStatus();
          connection = new MongoClient()
        }

        return this.connection
      }

      static currentRegionCount() {
          regionCount = //..
      }

      static getAvailableRegions() {
        return regionCount;
      }
    }
Enter fullscreen mode Exit fullscreen mode

With a static variable, you are able to cache the value without assigning new memory addresses to inner variables. If you would create a new Coordinate() or new Database() every-time the inner variables would precisely belong to the instance class.

Therefore when we call Database.getConnection we are referencing the same if a connection is established connection (it’s an example, we would have a listener). Which makes our code more performant and cleaner.

I, personally, have initialized too many classes in my life - creating multiple instances, exporting as an instance, exposing too many methods I never intended - making a big mess. JavaScript is a free spirit, but it needs some taming in order to write clean code.

Top comments (1)

Collapse
 
simon___4d27727af7778 profile image
Simon Hurst • Edited


```static getConnection() {
if (connection.timedOut() ||
!connection.established) {
Monitor.sendStatus();
connection = new MongoClient()
}

    return this.connection
  }
Enter fullscreen mode Exit fullscreen mode


Why in the above do you not right



```if (this.connection.timedOut() || ...```


Enter fullscreen mode Exit fullscreen mode