# Factory Design Pattern

One common problem in software development is object creation. In small applications, creating objects using the `new` keyword is straightforward. However, as applications grow, object creation logic often becomes scattered across multiple classes and services.

When different parts of the system need to decide which implementation to create, the code becomes harder to maintain, test, and extend.

The Factory Design Pattern helps solve this problem by centralizing object creation logic and hiding implementation details from the client.

### The Problem

Consider a credit card processing system that supports multiple card types:

*   Visa
    
*   MasterCard
    
*   American Express
    
*   RuPay
    

Without a factory, the application might contain code like this:

```java
if(type == CreditCardType.VISA) {
    card = new VisaCreditCard();
}
else if(type == CreditCardType.AMEX) {
    card = new AmexCreditCard();
}
else if(type == CreditCardType.MASTERCARD) {
    card = new MasterCardCreditCard();
}
else {
    card = new RupayCreditCard();
}
```

Initially this may seem reasonable.

However, as the application grows, this logic often gets duplicated across multiple services:

```text
PaymentService
BillingService
RewardService
CustomerService
```

Now every service knows:

*   Which concrete classes exist
    
*   How objects are created
    
*   Which implementation should be used
    

This creates tight coupling between business logic and object creation logic.

### Why Is This a Problem?

**Code Duplication**

The same object creation logic appears in multiple places.

**Tight Coupling**

Client code becomes dependent on concrete implementations.

```java
new VisaCreditCard()
new AmexCreditCard()
```

instead of depending on abstractions.

**Harder Maintenance**

Adding a new card type requires updating object creation logic everywhere it exists.

**Difficult Testing**

Directly creating concrete objects makes mocking and testing more difficult.

### The Factory Solution:

Instead of creating objects directly, we delegate object creation to a factory.

The client asks the factory for an object.

```java
CreditCard card =
    CreditCardFactory.create(type);
```

The factory decides which implementation should be returned.

The client only interacts with the `CreditCard` interface.

### Implementation

**Step 1: Create a Common Interface**

```java
public interface CreditCard {

    String getType();

    String getExpiry();
}
```

This interface defines the behavior that all credit cards must provide.

**Step 2: Create Concrete Implementations**

**Amex Credit Card**

```java
public class AmexCreditCard implements CreditCard {

    @Override
    public String getType() {
        return "Amex";
    }

    @Override
    public String getExpiry() {
        return "2030-11-12";
    }
}
```

**Visa Credit Card**

```java
public class VisaCreditCard implements CreditCard {

    @Override
    public String getType() {
        return "Visa";
    }

    @Override
    public String getExpiry() {
        return "2033-11-12";
    }
}
```

Similarly, we can create:

```java
MasterCardCreditCard
RupayCreditCard
```

All implementations follow the same contract.

**Step 3: Create an Enum**

```java
public enum CreditCardType {

    AMEX,
    MASTERCARD,
    VISA,
    RUPAY
}
```

This prevents invalid card types from being passed into the factory.

**Step 4: Create the Factory**

```java
public class CreditCardFactory {

    public static CreditCard create(
            CreditCardType type) {

        return switch(type) {

            case AMEX ->
                new AmexCreditCard();

            case MASTERCARD ->
                new MasterCardCreditCard();

            case VISA ->
                new VisaCreditCard();

            case RUPAY ->
                new RupayCreditCard();
        };
    }
}
```

The factory contains all object creation logic in a single place.

**Step 5: Client Usage**

```java
public class Main {

    public static void main(String[] args) {

        CreditCard card1 =
            CreditCardFactory.create(
                CreditCardType.AMEX);

        CreditCard card2 =
            CreditCardFactory.create(
                CreditCardType.VISA);

        System.out.println(
            card1.getType());

        System.out.println(
            card2.getType());
    }
}
```

Notice that the client never creates a concrete card directly.

The client only works with the abstraction.

# How the Flow Works

```text
Client
   |
   v
CreditCardFactory
   |
   +----> AmexCreditCard
   |
   +----> VisaCreditCard
   |
   +----> MasterCardCreditCard
   |
   +----> RupayCreditCard
```

The client does not need to know which implementation gets created.

That responsibility belongs entirely to the factory.

### Benefits of Using Factory Pattern

**Centralized Object Creation**

All creation logic exists in one place.

```java
CreditCardFactory
```

instead of being scattered throughout the application.

**Reduced Coupling**

The client depends on:

```java
CreditCard
```

rather than:

```java
VisaCreditCard
AmexCreditCard
MasterCardCreditCard
```

This makes the code more flexible.

**Easier Maintenance**

If object creation changes, only the factory needs to be updated.

Business logic remains untouched.

**Better Testability**

Clients can work against interfaces.

This makes mocking and dependency injection easier.

### `Limitations` :

The Factory Pattern is not free.

It introduces an additional layer of abstraction.

For small applications:

```java
new VisaCreditCard()
```

may be simpler than creating a factory.

Another common issue is large switch statements.

```java
switch(type) {
   ...
}
```

As the number of implementations grows, the factory can become harder to maintain.

In such cases, more advanced patterns like Factory Method or Abstract Factory may be better choices.

### Factory vs Factory Method vs Abstract Factory

These terms are often confused.

**Simple Factory**

Our credit card example is a Simple Factory.

```java
CreditCardFactory.create(type)
```

A single class decides which object to create.

## Factory Method

Object creation is delegated to subclasses.

```java
abstract class CreditCardFactory {

    abstract CreditCard createCard();
}
```

```java
class VisaFactory
        extends CreditCardFactory {

    CreditCard createCard() {
        return new VisaCreditCard();
    }
}
```

Each factory subclass decides which product to create.

## Abstract Factory

Abstract Factory creates families of related objects.

Example:

```text
IndiaPaymentFactory
    ├── RupayCreditCard
    └── RupayDebitCard

USPaymentFactory
    ├── VisaCreditCard
    └── VisaDebitCard
```

Instead of creating one object, it creates multiple related objects.

### When Should You Use Factory Pattern?

Use it when:

*   Multiple implementations exist
    
*   Object creation logic is duplicated
    
*   Client code should not know implementation details
    
*   Object creation becomes more complex over time
    

Examples include:

```text
Payment Gateways
Notification Systems
Storage Providers
Database Drivers
Messaging Systems
```

### Engineering Takeaways

The Factory Design Pattern is fundamentally about separating object creation from business logic.

Its primary goal is not to avoid the `new` keyword. The real value comes from reducing coupling and centralizing decisions about which implementation should be instantiated.

A useful rule of thumb is simple:

If multiple parts of the application are repeatedly deciding which implementation to create, that decision likely belongs inside a factory.

This keeps business logic focused on behavior while the factory remains responsible for construction.
