# Factory Method Design Pattern

## 1\. Introduction

Good morning, everyone.

Today we are going to understand the **Factory Method Design Pattern**.

Before understanding Factory Method, remember one important point:

> Creating an object is not always as simple as writing the `new` keyword.

In a small program, we can directly create an object:

```java
EmailNotification notification =
        new EmailNotification();
```

But in a large application:

*   We may have different types of objects.
    
*   Object creation may require configuration.
    
*   The required object may be decided at runtime.
    
*   We may want to add new object types in the future.
    

Factory Method helps us manage this object-creation problem.

* * *

## 2\. What is Coupling?

Coupling tells us how strongly two classes depend on each other.

Consider this code:

```java
class OrderService {

    public void placeOrder() {

        System.out.println("Order placed");

        EmailNotification notification =
                new EmailNotification();

        notification.send("Your order is confirmed");
    }
}
```

Here, `OrderService` directly creates an `EmailNotification`.

Therefore:

```text
OrderService depends on EmailNotification
```

This dependency between two classes is called **coupling**.

* * *

## 3\. What is Tight Coupling?

Tight coupling means that one class strongly depends on a particular concrete class.

In our example:

```java
EmailNotification notification =
        new EmailNotification();
```

`OrderService` knows:

*   The name of the concrete class
    
*   How its object is created
    
*   Which constructor it has
    
*   Which method it provides
    

Suppose the requirement changes from Email to SMS.

We will have to modify `OrderService`:

```java
SMSNotification notification =
        new SMSNotification();
```

This is a problem because the order-placement logic should not change just because the notification type has changed.

### Simple definition

> Tight coupling means a change in one class can force us to change other classes.

* * *

## 4\. What is Loose Coupling?

Loose coupling means that a class depends on an interface or abstraction instead of depending directly on a concrete class.

First, we create a common interface:

```java
interface Notification {

    void send(String message);
}
```

Different notification classes can implement it:

```java
class EmailNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println("Email sent: " + message);
    }
}
```

```java
class SMSNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println("SMS sent: " + message);
    }
}
```

Now our business code can work with the interface:

```java
Notification notification;
```

This reference can store different objects:

```java
notification = new EmailNotification();
notification = new SMSNotification();
```

The business code does not need to know the internal working of Email or SMS.

### Simple definition

> Loose coupling means that classes depend on a common contract and implementations can be replaced with minimum changes.

Loose coupling does not mean that dependencies completely disappear. It means that concrete dependencies are reduced and kept in controlled places.

* * *

## 5\. Is the `new` Keyword Wrong?

No, the `new` keyword is not wrong.

We must use `new` somewhere to create an object.

The problem starts when object-creation logic is spread throughout the business code.

Factory Method does not remove the `new` keyword.

> Factory Method moves the `new` keyword to a more appropriate place.

* * *

## 6\. The Main Problem

Suppose our application supports three notification types:

*   Email notification
    
*   SMS notification
    
*   Push notification
    

The common notification process is:

1.  Validate the message.
    
2.  Create a notification object.
    
3.  Send the message.
    
4.  Store a log.
    

The process is the same for all notifications.

Only the object changes:

```text
Email service creates EmailNotification
SMS service creates SMSNotification
Push service creates PushNotification
```

We want the common process to remain in a parent class, but we want child classes to decide which object should be created.

This is where we use the Factory Method Pattern.

* * *

## 7\. Factory Method Definition

> Factory Method is a creational design pattern in which a parent Creator class defines a method for creating an object, but its child classes decide which concrete object should be created.

In simple words:

> The parent says, “Create an object.” The child says, “I will decide which object to create.”

* * *

## 8\. Structure of Factory Method

Factory Method normally contains the following parts:

| Role | Responsibility |
| --- | --- |
| Product | Defines the common behaviour |
| Concrete Product | Provides the actual implementation |
| Creator | Declares the Factory Method |
| Concrete Creator | Overrides the Factory Method and creates a Product |
| Client | Uses the Creator |

In our example:

| Role | Class |
| --- | --- |
| Product | `Notification` |
| Concrete Products | `EmailNotification`, `SMSNotification` |
| Creator | `NotificationService` |
| Factory Method | `createNotification()` |
| Concrete Creators | `EmailNotificationService`, `SMSNotificationService` |
| Client | `Main` |

* * *

## 9\. Step One: Product Interface

```java
interface Notification {

    void send(String message);
}
```

`Notification` is called the **Product interface**.

It defines a common contract:

> Every notification must provide a `send()` method.

Email and SMS may send messages differently, but the client can use both through the same method:

```java
notification.send(message);
```

* * *

## 10\. Step Two: Concrete Products

```java
class EmailNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println("Email sent: " + message);
    }
}
```

```java
class SMSNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println("SMS sent: " + message);
    }
}
```

```java
class PushNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println(
                "Push notification sent: " + message
        );
    }
}
```

These are called **Concrete Products** because these are the actual objects created by our Factory Methods.

* * *

## 11\. Step Three: Creator Class

```java
abstract class NotificationService {

    protected abstract Notification createNotification();

    public void notifyUser(String message) {

        if (message == null || message.isBlank()) {
            throw new IllegalArgumentException(
                    "Message cannot be empty"
            );
        }

        System.out.println("Validating message");

        Notification notification =
                createNotification();

        notification.send(message);

        System.out.println("Saving notification log");
    }
}
```

`NotificationService` is called the **Creator class**.

It contains two important methods.

### Factory Method

```java
protected abstract Notification createNotification();
```

This is the actual Factory Method.

The parent class knows that it needs a `Notification` object, but it does not know whether that object will be:

*   `EmailNotification`
    
*   `SMSNotification`
    
*   `PushNotification`
    

The child classes will make that decision.

### Business Method

```java
public void notifyUser(String message)
```

This method contains the common notification workflow:

```text
Validate → Create → Send → Log
```

The common workflow stays in the parent class because it is the same for every notification.

* * *

## 12\. Why is the Factory Method Abstract?

Suppose the parent class creates Email directly:

```java
public Notification createNotification() {
    return new EmailNotification();
}
```

Now the parent class is connected to `EmailNotification`.

It is no longer general.

Therefore, we make the method abstract:

```java
protected abstract Notification createNotification();
```

This tells every child class:

> You must decide which Notification object should be created.

* * *

## 13\. Step Four: Concrete Creators

### Email Creator

```java
class EmailNotificationService
        extends NotificationService {

    @Override
    protected Notification createNotification() {
        return new EmailNotification();
    }
}
```

This child class decides that an `EmailNotification` should be created.

### SMS Creator

```java
class SMSNotificationService
        extends NotificationService {

    @Override
    protected Notification createNotification() {
        return new SMSNotification();
    }
}
```

### Push Creator

```java
class PushNotificationService
        extends NotificationService {

    @Override
    protected Notification createNotification() {
        return new PushNotification();
    }
}
```

These classes are called **Concrete Creators**.

Every Concrete Creator creates its corresponding Concrete Product.

* * *

## 14\. Client Code

```java
public class Main {

    public static void main(String[] args) {

        NotificationService service =
                new EmailNotificationService();

        service.notifyUser(
                "Your order has been confirmed"
        );
    }
}
```

Output:

```text
Validating message
Email sent: Your order has been confirmed
Saving notification log
```

For SMS, we only change the Creator:

```java
NotificationService service =
        new SMSNotificationService();

service.notifyUser("Your OTP is 4582");
```

The method call remains the same:

```java
service.notifyUser(message);
```

* * *

## 15\. Execution Flow

Consider this line:

```java
NotificationService service =
        new EmailNotificationService();
```

The reference type is:

```java
NotificationService
```

The actual object is:

```java
EmailNotificationService
```

Now we call:

```java
service.notifyUser("Order confirmed");
```

The following steps happen:

1.  `notifyUser()` starts message validation.
    
2.  It calls `createNotification()`.
    
3.  The actual object is `EmailNotificationService`.
    
4.  Therefore, the overridden Factory Method of `EmailNotificationService` executes.
    
5.  It creates and returns an `EmailNotification`.
    
6.  The parent class stores it inside a `Notification` reference.
    
7.  It calls `notification.send(message)`.
    
8.  The Email implementation sends the message.
    
9.  Finally, the log is saved.
    

* * *

## 16\. Where is Polymorphism Used?

Factory Method uses polymorphism at two levels.

### Creator polymorphism

```java
NotificationService service =
        new EmailNotificationService();
```

A parent reference stores a child Creator object.

### Product polymorphism

```java
Notification notification =
        new EmailNotification();
```

An interface reference stores a Concrete Product object.

Therefore, Factory Method combines:

*   Abstraction
    
*   Inheritance
    
*   Method overriding
    
*   Runtime polymorphism
    

* * *

## 17\. Where is Loose Coupling?

Look at the parent business workflow:

```java
Notification notification =
        createNotification();

notification.send(message);
```

The parent does not write:

```java
EmailNotification notification =
        new EmailNotification();
```

The parent only knows the `Notification` interface.

Therefore, the common business workflow is not directly dependent on Email, SMS or Push.

The Concrete Creator still knows its Concrete Product:

```java
return new EmailNotification();
```

That is acceptable because object creation is the responsibility of the Concrete Creator.

> Factory Method does not completely remove concrete dependencies. It isolates them inside small, dedicated Creator classes.

* * *

## 18\. Adding WhatsApp Notification

Suppose we want to add WhatsApp notifications.

First, we add a new Product:

```java
class WhatsAppNotification
        implements Notification {

    @Override
    public void send(String message) {
        System.out.println(
                "WhatsApp message sent: " + message
        );
    }
}
```

Then, we add its Creator:

```java
class WhatsAppNotificationService
        extends NotificationService {

    @Override
    protected Notification createNotification() {
        return new WhatsAppNotification();
    }
}
```

Client code:

```java
NotificationService service =
        new WhatsAppNotificationService();

service.notifyUser("Payment successful");
```

We did not modify:

*   `NotificationService`
    
*   `EmailNotificationService`
    
*   `SMSNotificationService`
    
*   `PushNotificationService`
    

We extended the application by adding new classes.

This gives better support for the **Open/Closed Principle**:

> Software should be open for extension but closed for unnecessary modification.

* * *

## 19\. Complete Java Program

```java
interface Notification {

    void send(String message);
}

class EmailNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println("Email sent: " + message);
    }
}

class SMSNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println("SMS sent: " + message);
    }
}

class PushNotification implements Notification {

    @Override
    public void send(String message) {
        System.out.println(
                "Push notification sent: " + message
        );
    }
}

abstract class NotificationService {

    protected abstract Notification createNotification();

    public void notifyUser(String message) {

        if (message == null || message.isBlank()) {
            throw new IllegalArgumentException(
                    "Message cannot be empty"
            );
        }

        System.out.println("Validating message");

        Notification notification =
                createNotification();

        notification.send(message);

        System.out.println("Saving notification log");
    }
}

class EmailNotificationService
        extends NotificationService {

    @Override
    protected Notification createNotification() {
        return new EmailNotification();
    }
}

class SMSNotificationService
        extends NotificationService {

    @Override
    protected Notification createNotification() {
        return new SMSNotification();
    }
}

class PushNotificationService
        extends NotificationService {

    @Override
    protected Notification createNotification() {
        return new PushNotification();
    }
}

public class Main {

    public static void main(String[] args) {

        NotificationService emailService =
                new EmailNotificationService();

        emailService.notifyUser(
                "Your order has been confirmed"
        );

        System.out.println();

        NotificationService smsService =
                new SMSNotificationService();

        smsService.notifyUser(
                "Your OTP is 4582"
        );

        System.out.println();

        NotificationService pushService =
                new PushNotificationService();

        pushService.notifyUser(
                "Your order is out for delivery"
        );
    }
}
```

* * *

## 20\. Simple Factory vs Factory Method

### Simple Factory

A single Factory class decides which object to create:

```java
if (type.equals("EMAIL")) {
    return new EmailNotification();
}

if (type.equals("SMS")) {
    return new SMSNotification();
}
```

### Factory Method

The parent declares a Factory Method:

```java
protected abstract Notification createNotification();
```

Different child Creators override it:

```java
class EmailNotificationService {

    protected Notification createNotification() {
        return new EmailNotification();
    }
}
```

| Simple Factory | Factory Method |
| --- | --- |
| One Factory handles every type | Different Creator subclasses |
| Usually uses `if-else` or `switch` | Uses inheritance and overriding |
| Factory decides the Product | Child Creator decides the Product |
| Easier for small applications | Better for extensible workflows |
| Factory changes for a new Product | A new Creator can be added |

* * *

## 21\. Advantages

### Loose coupling

The common workflow depends on the Product interface, not on individual Concrete Products.

### Reusable workflow

Validation, sending and logging logic remains in one parent Creator class.

### Easy extension

New Product and Creator classes can be added without changing the existing workflow.

### Controlled object creation

The responsibility of creating objects remains inside Creator classes.

### Better maintainability

A change in one Product’s creation logic is normally handled by its corresponding Creator.

* * *

## 22\. Disadvantages

### More classes

Every new Product may require a new Concrete Creator.

### More complex structure

Students must understand two hierarchies:

*   Product hierarchy
    
*   Creator hierarchy
    

### Overengineering for simple problems

If the application has only one simple object type, Factory Method may add unnecessary complexity.

* * *

## 23\. When Should We Use Factory Method?

Use Factory Method when:

*   Multiple implementations share a common interface.
    
*   A common workflow needs different objects.
    
*   Child classes should decide which object to create.
    
*   The exact object type may change or grow in the future.
    
*   We want to keep object-creation details away from common business logic.
    

Examples include:

*   Email, SMS and Push notifications
    
*   Road, Sea and Air logistics
    
*   PDF, Word and Excel documents
    
*   MySQL and PostgreSQL connections
    
*   Windows and Web user-interface components
    

* * *

## 24\. When Should We Not Use It?

Avoid Factory Method when:

*   There is only one simple object type.
    
*   Object creation is unlikely to change.
    
*   There is no common workflow.
    
*   Creating additional Creator subclasses provides no real benefit.
    

Design patterns should solve real problems. We should not add a pattern only to make the code look advanced.

* * *

## 25\. Common Student Confusion

### Is every method that creates an object a Factory Method?

No.

This is only an object-creation method:

```java
public Notification createNotification() {
    return new EmailNotification();
}
```

The Factory Method Pattern normally involves:

*   A parent Creator
    
*   A Factory Method
    
*   Child Creators overriding that method
    
*   Child Creators deciding which Product to instantiate
    
*   A common parent workflow using the returned Product
    

### Does Factory Method remove the `new` keyword?

No. It places `new` inside the responsible Concrete Creator.

### Who decides which object will be created?

The Concrete Creator decides.

### Why does the Factory Method return `Notification`?

Because it may return any class that implements `Notification`.

* * *

## 26\. Final Classroom Summary

Factory Method is a Creational Design Pattern.

It separates:

```text
What work should be performed
```

from:

```text
Which object should perform that work
```

The parent Creator manages the common workflow.

The child Creator decides which Concrete Product should be created.

This reduces direct dependency between business logic and Concrete Product classes.

### Final definition

> Factory Method defines a method for creating an object, but allows subclasses to decide which concrete object should be instantiated.

### Golden line

> The parent decides the process, while the child decides the Product.

### Loose-coupling golden line

> Loose coupling means depending on a common contract instead of strongly depending on one particular implementation.
