Skip to main content

Singleton Design Pattern Real World Application

Singletons are often used in situations where system-wide actions need to be coordinated from a single central place. An example of such a use case is a logging service.

Consider an application where you want to write logs to a file. You might want to ensure that only a single instance of the logger is created, to avoid issues with file permissions when multiple instances try to write to the same log file.

Here is how we might create a Logger singleton in TypeScript:

class Logger {
private static instance: Logger;

private constructor() {}

public static getInstance(): Logger {
if (!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}

public log(message: string): void {
const timestamp = new Date();
console.log(`[${timestamp.toLocaleString()}] - ${message}`);
}
}

// Usage
const logger1 = Logger.getInstance();
logger1.log("First log message");

const logger2 = Logger.getInstance();
logger2.log("Second log message");

console.log(logger1 === logger2); // true

In the above code, Logger is a singleton class with a log method. The log method logs messages with a timestamp.

We ensure that only a single instance of Logger is created by maintaining a static instance of the class, and providing a static getInstance method which creates a new instance only if one doesn't already exist.

The log method can be used to log messages from anywhere in your application, and because we're using a singleton, you're guaranteed that all log messages go to the same place, even when they're called from different parts of your application.

The last line (console.log(logger1 === logger2);) checks if logger1 and logger2 refer to the same object, which they do, hence it logs true to the console. This confirms that there is indeed only a single instance of Logger.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.

SEE COURSE DETAILS

Why Do We Need A Singleton Here?

The Logger class is often made a singleton to maintain a centralized and synchronized logging system in an application. Here are some reasons why it is beneficial:

  1. File Access Issues: If each instance of the Logger class attempts to write to the same log file, you might run into concurrency and file access issues. Multiple instances may cause file writing conflicts where one logger could overwrite the data of another, leading to loss of data and inconsistency.

  2. Performance: Opening and closing file connections are resource-intensive operations. If each logger opens its file connection, it can put unnecessary stress on the system resources. A single instance sharing the same file connection can be more efficient.

  3. Consistency: By having a single instance, you can ensure that all parts of your application use the same logging format and write to the same place. If there were multiple logger instances, different parts of your application might log messages differently or to different places.

  4. Configuration: If each part of your application uses a separate logger, and you want to change something about the logging (like the log format or log level), you would have to find and change every instance of the logger. With a singleton, there's only one place you need to change.

While the singleton pattern provides many benefits for a logger, it's worth mentioning that you should ensure that the logger is thread-safe if your application has multi-threading, otherwise it might still face issues with concurrent writes.

What Can You Do Next 🙏😊

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.

YouTube @cloudaffle