Difference between singleton and factory method pattern

Learn difference between singleton and factory method pattern with practical examples, diagrams, and best practices. Covers design-patterns development techniques with visual explanations.

Singleton vs. Factory Method: Understanding Design Pattern Choices

Hero image for Difference between singleton and factory method pattern

Explore the fundamental differences between the Singleton and Factory Method design patterns, their use cases, advantages, and disadvantages to help you choose the right pattern for your object creation needs.

Design patterns are reusable solutions to common problems in software design. Among the creational patterns, Singleton and Factory Method are frequently discussed, yet often confused. While both deal with object creation, they serve distinct purposes and address different design challenges. This article will delve into their core principles, illustrate their implementations, and provide guidance on when to use each.

The Singleton Pattern: Ensuring a Single Instance

The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. It's often used for logging, configuration management, or managing a single connection pool. The key idea is to prevent multiple instantiations of a class, thereby controlling resource usage or ensuring consistent state across an application.

classDiagram
    class Singleton {
        -static instance: Singleton
        -Singleton()
        +static getInstance(): Singleton
        +businessLogic()
    }
    Singleton "1" -- "1" Client : uses

Class diagram for the Singleton pattern

public class Singleton {
    private static Singleton instance;

    // Private constructor to prevent instantiation from other classes
    private Singleton() {}

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

    public void showMessage() {
        System.out.println("Hello from Singleton!");
    }
}

// Usage
public class Application {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();

        System.out.println(s1 == s2); // true, both refer to the same instance
        s1.showMessage();
    }
}

Java implementation of the Singleton pattern

The Factory Method Pattern: Delegating Object Creation

The Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. It promotes loose coupling by allowing a class to defer instantiation to its subclasses. This pattern is particularly useful when a class cannot anticipate the class of objects it needs to create, or when a library needs to provide a way for clients to extend its internal components.

classDiagram
    direction LR
    class Creator {
        +abstract factoryMethod(): Product
        +anOperation(): String
    }
    class ConcreteCreatorA {
        +factoryMethod(): Product
    }
    class ConcreteCreatorB {
        +factoryMethod(): Product
    }
    class Product {
        +operation(): String
    }
    class ConcreteProductA {
        +operation(): String
    }
    class ConcreteProductB {
        +operation(): String
    }

    Creator <|-- ConcreteCreatorA
    Creator <|-- ConcreteCreatorB
    Product <|-- ConcreteProductA
    Product <|-- ConcreteProductB
    Creator ..> Product : creates

Class diagram for the Factory Method pattern

// Product Interface
public interface IProduct
{
    string GetName();
}

// Concrete Products
public class ConcreteProductA : IProduct
{
    public string GetName() => "Product A";
}

public class ConcreteProductB : IProduct
{
    public string GetName() => "Product B";
}

// Creator Abstract Class
public abstract class Creator
{
    public abstract IProduct FactoryMethod();

    public string AnOperation()
    {
        // Call the factory method to create a Product object.
        IProduct product = FactoryMethod();
        return $"Creator: The same creator's code has just worked with {product.GetName()}";
    }
}

// Concrete Creators
public class ConcreteCreatorA : Creator
{
    public override IProduct FactoryMethod()
    {
        return new ConcreteProductA();
    }
}

public class ConcreteCreatorB : Creator
{
    public override IProduct FactoryMethod()
    {
        return new ConcreteProductB();
    }
}

// Usage
public class Client
{
    public void Main()
    {
        Console.WriteLine("App: Launched with the ConcreteCreatorA.");
        ClientCode(new ConcreteCreatorA());

        Console.WriteLine("\nApp: Launched with the ConcreteCreatorB.");
        ClientCode(new ConcreteCreatorB());
    }

    public void ClientCode(Creator creator)
    {
        Console.WriteLine(creator.AnOperation());
    }
}

C# implementation of the Factory Method pattern

Key Differences and When to Use Each

The core distinction lies in their intent. Singleton focuses on restricting the number of instances to one, providing a global access point. Factory Method focuses on delegating the responsibility of object creation to subclasses, allowing for flexible and extensible object instantiation without exposing the creation logic to the client. Choosing between them depends entirely on your specific requirements for object creation and management.

Hero image for Difference between singleton and factory method pattern

Comparison of Singleton vs. Factory Method

When to use Singleton:

  • Global Access Point: When you need a single, globally accessible instance of a class, such as a configuration manager, logger, or a single database connection pool.
  • Resource Control: When you want to control access to a shared resource and ensure that only one instance is managing it.
  • State Management: When a single, consistent state is required across the application for a particular component.

When to use Factory Method:

  • Decoupling Creation: When a class can't anticipate the class of objects it needs to create, and you want to decouple the client code from the concrete product classes.
  • Extensibility: When you want to provide a framework or library that allows clients to extend its internal components by defining new types of objects.
  • Complex Object Creation: When the object creation process is complex and involves multiple steps or conditional logic, which can be encapsulated within the factory method.
  • Polymorphic Creation: When you need to create different types of objects based on some input or configuration, and these objects share a common interface or base class.