DEV Community

Tomas Eglinskas
Tomas Eglinskas

Posted on

1 3

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.

Image of Timescale

📊 Benchmarking Databases for Real-Time Analytics Applications

Benchmarking Timescale, Clickhouse, Postgres, MySQL, MongoDB, and DuckDB for real-time analytics. Introducing RTABench 🚀

Read full post →

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

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay