VOOZH about

URL: https://www.javacodegeeks.com/2025/09/design-patterns-revisited-are-singleton-and-factory-still-relevant.html

⇱ Design Patterns Revisited: Are Singleton and Factory Still Relevant? - Java Code Geeks


Software design patterns are often described as the timeless building blocks of software engineering. They originated from the famous “Gang of Four” (GoF) book published in 1994, which categorized patterns into creational, structural, and behavioral families. Among them, Singleton and Factory patterns have been two of the most widely used—and hotly debated—over the years.

But in today’s world of microservices, dependency injection, and functional programming, do these patterns still hold relevance? Let’s revisit them with modern eyes.

The Singleton Pattern: Friend or Foe?

The Singleton pattern ensures a class has only one instance and provides a global access point to it. Think of it like having a single manager in an office who coordinates resources.

Classic Implementation (Java Example)

public class Singleton {
 private static Singleton instance;

 private Singleton() { }

 public static synchronized Singleton getInstance() {
 if (instance == null) {
 instance = new Singleton();
 }
 return instance;
 }
}

This ensures only one object is created and reused throughout the application.

Why Developers Loved It

  • Global state management: Easy access to shared resources like loggers, caches, or configuration.
  • Memory efficiency: Prevents redundant instantiations.

Why Developers Hate It

  • Hidden dependencies: Any class accessing the singleton is tightly coupled to it.
  • Testing nightmare: Mocking singletons is cumbersome.
  • Global state is risky: Makes applications less predictable in multi-threaded environments.

The Factory Pattern: Shaping Object Creation

The Factory Method or Factory Class provides a way to create objects without specifying the exact class of the object that will be created. It’s about delegating the “new” keyword to a dedicated creator.

Example (Python)

class Shape:
 def draw(self):
 pass

class Circle(Shape):
 def draw(self):
 print("Drawing a Circle")

class Square(Shape):
 def draw(self):
 print("Drawing a Square")

class ShapeFactory:
 @staticmethod
 def get_shape(shape_type):
 if shape_type == "circle":
 return Circle()
 elif shape_type == "square":
 return Square()
 return None

shape = ShapeFactory.get_shape("circle")
shape.draw()

Here, the client code doesn’t need to know how a Circle or Square is instantiated—just asks the factory.

Relevance in Today’s World

PatternThen (1990s–2000s)Now (Cloud, Microservices, DI)
SingletonSimplified global access to resources.Often replaced by dependency injection containers, environment configs, or service registries. Used carefully in logging or caching scenarios.
FactoryDecoupled object creation logic.Still highly relevant. Factories form the backbone of frameworks (Spring, Angular, Django) that manage object lifecycles dynamically.

Visualizing the Difference

Here’s a simplified diagram to compare the patterns:

Singleton:
 ┌────────────┐
 │ Client │
 └─────┬──────┘
 │
 ┌─────▼──────┐
 │ Singleton │───> One global instance
 └────────────┘

Factory:
 ┌────────────┐
 │ Client │
 └─────┬──────┘
 │
 ┌─────▼──────┐
 │ Factory │───> Creates many different objects
 └────────────┘

The Singleton centralizes state, while the Factory centralizes object creation.

A Real-World Example: Logging System

To really see the differences, let’s imagine building a logging system. Applications need logs everywhere, and they are a great use case to compare Singleton and Factory.

Singleton Approach

With Singleton, the logging system ensures only one global logger instance exists.

// Logger using Singleton
public class Logger {
 private static Logger instance;

 private Logger() { }

 public static synchronized Logger getInstance() {
 if (instance == null) {
 instance = new Logger();
 }
 return instance;
 }

 public void log(String message) {
 System.out.println("[LOG] " + message);
 }
}

// Client
public class App {
 public static void main(String[] args) {
 Logger logger = Logger.getInstance();
 logger.log("Application started");
 }
}

Pros

  • Always the same logger across the entire application.
  • Easy to use, no setup required.

Cons

  • Harder to replace with a mock logger in tests.
  • Not flexible if we want different loggers (e.g., file logger vs. console logger).

Factory Approach

Now, let’s use a Factory. Instead of a single logger, we can ask a factory to give us the type of logger we need.

// Logger interface
public interface Logger {
 void log(String message);
}

// Console logger
public class ConsoleLogger implements Logger {
 public void log(String message) {
 System.out.println("[Console] " + message);
 }
}

// File logger
public class FileLogger implements Logger {
 public void log(String message) {
 // imagine writing to a file
 System.out.println("[File] " + message);
 }
}

// Logger Factory
public class LoggerFactory {
 public static Logger getLogger(String type) {
 switch (type.toLowerCase()) {
 case "file":
 return new FileLogger();
 case "console":
 default:
 return new ConsoleLogger();
 }
 }
}

// Client
public class App {
 public static void main(String[] args) {
 Logger consoleLogger = LoggerFactory.getLogger("console");
 consoleLogger.log("Application started on console");

 Logger fileLogger = LoggerFactory.getLogger("file");
 fileLogger.log("Application started in file");
 }
}

Pros

  • Very flexible: choose different loggers depending on environment or configuration.
  • Easier to extend (add DatabaseLogger, CloudLogger, etc. without changing client code).
  • More testable (inject a mock logger if needed).

Cons

  • More setup and boilerplate.
  • Not always necessary if you only ever need one logger.

Side-by-Side Comparison

AspectSingleton LoggerFactory Logger
InstancesOne global instanceMultiple instances depending on need
FlexibilityRigid: only one logger typeFlexible: can support many loggers
TestingHard to mockEasy to inject mocks
Use CaseGlobal configuration, cache, shared statePluggable systems, extensibility

Which Should You Use?

  • If your app truly requires one global logger (e.g., centralized configuration in a small app), a Singleton is fine.
  • If you’re building a scalable system with different logging backends (console, file, cloud), a Factory is more future-proof.

👉 This practical example shows how Singleton trades flexibility for simplicity, while Factory trades simplicity for flexibility.

Modern Best Practices

  • Singletons: Use sparingly. In modern applications, dependency injection frameworks (e.g., Spring in Java, Dagger/Hilt in Android, or NestJS in Node.js) provide controlled, testable ways to manage shared resources.
  • Factories: Still powerful! They are especially valuable in situations like:
    • Plug-in architectures (e.g., choosing different payment providers).
    • Creating objects with complex setup logic.
    • Framework-level abstractions where the client shouldn’t care about object internals.

Final Thoughts

Are Singleton and Factory still relevant?

  • Singleton: less relevant as a design pattern because frameworks now handle instance management better. But conceptually, a single shared instance still makes sense in logging, caching, and configurations.
  • Factory: very much alive and thriving, serving as the backbone of modern frameworks and architectures.

So instead of asking if these patterns are still useful, a better question might be: In what context should I apply them today?

Further Reading

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

👁 Photo of Eleftheria Drosopoulou
Eleftheria Drosopoulou
September 22nd, 2025Last Updated: September 17th, 2025
0 443 4 minutes read

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button
Close
wpDiscuz