Comparing Static Factory Methods and Constructors

This question led to an interesting discussion in the comments, focusing on the advantages of Static Factory Methods versus Constructors.

Consider the following example:

export class User extends Model<UserProps> {

  // Recommended Method (Without a constructor)
  static buildUser(attrs: UserProps) : User {
    return new User(new Attributes(attrs), new Eventing(), new ApiSync(rootUrl));
  }

  // Alternatively, why not do it this way? No need to call User.buildUser()
  constructor(attrs: UserProps) {
    super(new Attributes(attrs), new Eventing(), new ApiSync(rootUrl));
  }
}

I realize that by only implementing the buildUser method, the constructor with super and arguments will be implicitly called if the constructor is not defined explicitly.

However, are there any features that buildUser provides which a direct super call within the constructor does not?

It just seems like extra code to create a user.

let user = User.buildUser(some attr)

versus

let user = new User(some attr);

Answer №1

Please note: The focus of this question is on Object-Oriented Programming principles rather than TypeScript. I will be providing examples in Java as it is my preferred language. However, the concepts discussed are universal and should be easily understood by any programmer.

Naming

Consider the following example:

   final Duration a = new Duration (1); // Represents 1 hour
   final Duration a = new Duration (0, 1); // Represents 1 minute
   final Duration a = new Duration (0, 0, 1); // Represents 1 second
   final Duration a = new Duration (0, 0, 0, 1); // Represents 1 millisecond

   final Duration a = Duration.ofHours(1); // Represents 1 hour
   final Duration a = Duration.ofMinutes(1); // Represents 1 minute
   final Duration a = Duration.ofSeconds(1); // Represents 1 second
   final Duration a = Duration.ofMillis(1); // Represents 1 millisecond

The primary advantage of static factory methods: They provide meaningful names

Caching

Consider the following example:

private static final Map <Integer, Duration> CACHE = Maps.newHashMap();

public static Duration ofHours(final int value) {
        return Duration.CACHE.computeIfAbsent(
            value, v -> new Duration(v);
        );
    }
}

The second advantage of static factory methods: They can cache instances

Subtyping

Consider the following example:

public static Duration ofHours(final int value) {

    if(value < 24)
        return new Duration(value, 0, 0, 0);
    else
        return new MultiDayDuration(...);
}

public static class MultiDayDuration extends Duration {
   ...
}

The third advantage of static factory methods: They can create subtype instances

Answer №2

@Crocsx's response highlights the benefits of Static Factories over Constructor-only implementations, with specific examples. Check it out here:

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Purge the inversify-js container and fetch fresh service instances

My frontend application in react-native utilizes inversify-js for service classes. I have implemented an IOC structure where services are shared as singleton instances, each with an init/destroy method to manage internal state. While the init/destroy mec ...

What is the process of defining a constructor for Python's latest NamedTuple variation?

Did you know that the most recent way to define named tuples in Python is like this: from typing import NamedTuple class MyType(NamedTuple): id: int = 0 name: str = 0 Once you define the type, the Python interpreter automatically creates defaul ...

Embracing the "export ... from" feature in the TypeScript compiler

Can the tsc compiler handle this particular export statement? export {PromiseWrapper, Promise, PromiseCompleter} from 'angular2/src/facade/promise'; Your assistance is greatly appreciated! ...

Using Typescript's mapped types to apply a single value type to all values across different key types

Having two different key types, OneOf and FeildType, to distinguish between the two types, I initially tried creating the following type but it ended up combining the member types. interface TypeMap { [key: number]: FeildType [key: string]: OneOf } ...

Issue with ESLint error in TypeScript PrimeReact async Button click handler

I am currently facing an issue with exporting data from a DataTable in PrimeReact. The onClick function for the Button does not allow async callbacks as flagged by eslint. Can someone guide me on how to properly call this function? const exportCSV = us ...

Using Promise.all for multiple function calls

I have several functions set up like this: private async p1(): Promise<Result> { let p1; // Do some operations. return p1; } private async p5(): Promise<void> { // Make a call to an external API. } Some of these functions c ...

The unexpected identifier 'express' was encountered in the import call, which requires either one or two arguments

I'm in the process of constructing an express server using typescript and Bun. Recently, I completed my register route: import express from "express"; const router = express.Router(); router.get('/registerUser',(_req:express.Reque ...

Tips for outputting data in TypeScript when a search form is updated

Below is the structure of my HTML file: <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type"" content="text/html; charset=utf-8"/> </head> <body> <input ...

What is the best approach for initializing and adding dataset in a database using Nest.JS when launching the application for the first time?

In managing my database, I have multiple tables that require default information such as categories, permissions, roles, and tags. It is crucial for me to ensure that this exact information has consistent IDs whenever the application is freshly launched on ...

The problem with reflect-metadata - __webpack_require__ arises from the absence of the 'Require' definition

I'm facing an issue while trying to launch my angular app in Visual Studio. It seems to be stuck on the "Loading..." section. Upon checking Chrome's error console, I came across the following error: https://i.sstatic.net/1aSZT.jpg Uncaught R ...

To successfully import files in Sveltekit from locations outside of /src/lib, make sure to include the .ts extension in the import statement

Currently, I am working on writing tests with Playwright within the /tests directory. I want to include some helper functions that can be placed in the /tests/lib/helpers folder. When the import does not specifically have a .ts extension, tests throw a mo ...

Utilizing TypeScript Modules for Enhanced Ambient Environments in Node.js

Currently, I am working on creating an ambient module in node.js by utilizing the Visual Studio developer tools. This is what the module code structure looks like: module "Module" { export class Class { first = "First"; second = "Second" ...

In TypeScript, leveraging the spread operator to determine the largest value in an array containing nullable numbers

Having an array of nullable numbers presented in the following way: let myArray : Array<number | null> = [1,2,null,4,null,5]; let maximumOfMyArray = Math.max(...myArray); // Type null is not assignable to type number I am content with JavaScript tre ...

Create dynamic modals in ReactJS that appear when a row is clicked

Engaged in a project for an undisclosed entity where patient data is retrieved from their API and displayed as modal on the page. Clicking on a modal reveals more threat information in another modal. The objective is for these modals to render based on a c ...

Is importing all models into every component considered poor practice?

At my workplace, there is a practice in the legacy code where every single model is imported into all components, regardless of whether they are needed or not. For example: import * as models from '../../view-models/models' ....... let parrot: m ...

cssclassName={ validatorState === RIGHT ? 'valid' : 'invalid' }

Is there a way to dynamically add different classes based on validation outcomes in React? My current implementation looks like this: className={ validatorState === RIGHT ? 'ok' : 'no' } However, I also need to handle cases where the ...

Is there a way in Typescript to dynamically create a type based on an array of potential values?

I am seeking a solution to dynamically define a type based on an array of possibilities. Within the provided map, the keys represent the type's name, while the corresponding values are arrays containing possible options for that type. export const ty ...

Uniqueness in TypeScript tuples: ensuring no duplicates

Solving the Problem Imagine we have a React component called X that requires input from properties Input. These properties include a field known as bounds. The bounds consist of a tuple containing 1-4 string literals: alpha, beta, gamma, delta. Objective ...

Deriving variable function parameters as object or tuple type in TypeScript

Searching for a similar type structure: type ArgsType<F extends Function> = ... which translates to ArgsType<(n: number, s: string)=>void> will result in [number, string] or {n: number, s: string} Following one of the provided solu ...

Growing React ecosystem resembling that of Angular

Angular appears to come with everything which for the client-side. On the other hand, React comes by itself. Are there any common consensus on how to get expand React/React Native with typescript in order to get a similar experience as with Angular. Are ...