Home > Java > javaTutorial > Understanding the Factory Method Pattern

Understanding the Factory Method Pattern

Susan Sarandon
Release: 2025-01-05 10:49:41
Original
861 people have browsed it

Understanding the Factory Method Pattern

Introduction

Hi everyone, I am writing this post to share my knowledge as I continue learning about design patterns. Today, I will present the Factory Method Pattern, which is a design pattern commonly used in real-world applications. If there are any mistakes in my post, please feel free to comment below, and I will gladly fix and update it.

Factory method pattern provides an interface for creating objects in a superclass, but allow subclasses to alter the type of objects that will be created.

Problem

Assume you have a bank application, and you’re building a feature for transferring money through various methods like bank transfer, paypal transfer,…

Before using the Factory Method pattern, let’s examine the scenario without it.

I will give an example implemented in Java.

Situation: Person1 sends money to Person2 using a transfer method (Bank Transfer or PayPal Transfer).

Folder structure:

problem/
├─ BankApp.java
├─ service/
│  ├─ PaypalTransferPayment.java
│  ├─ BankTransferPayment.java
├─ data/
│  ├─ Person.java
Copy after login
Copy after login

In the main application, create two persons with default amounts of money.

package problem;

import problem.data.Person;

public class BankApp {
    public static void main(String[] args) {
        Person person1 = new Person("John", 1000);
        Person person2 = new Person("Jane", 500);
    }
}
Copy after login
Copy after login

Create BankTransferPayment and PaypalTransferPayment classes.

package problem.service;

import problem.data.Person;

public class BankTransferPayment {
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Bank transfer payment success.");
    }
}
Copy after login
Copy after login
package problem.service;

import problem.data.Person;

public class PaypalPayment {
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Paypal transfer payment success.");
    }
}
Copy after login

Implement the logic in the main function.

package problem;

import problem.data.Person;
import problem.service.BankTransferPayment;
import problem.service.PaypalPayment;

public class BankApp {
    public static void main(String[] args) {
        Person person1 = new Person("John", 1000);
        Person person2 = new Person("Jane", 500);

        String paymentMethod = "BANK_TRANSFER";

        if (paymentMethod.equals("BANK_TRANSFER")) {
            BankTransferPayment bankTransferPayment = new BankTransferPayment();
            bankTransferPayment.processPayment(person1, person2, 100);

            System.out.println("===Method bank_transfer===");
            System.out.println(person1.getName() + " has " + person1.getAmount());
            System.out.println(person2.getName() + " has " + person2.getAmount());
        } else if (paymentMethod.equals("PAYPAL")) {
            PaypalPayment paypalPayment = new PaypalPayment();
            paypalPayment.processPayment(person1, person2, 100);

            System.out.println("===Method paypal===");
            System.out.println(person1.getName() + " has " + person1.getAmount());
            System.out.println(person2.getName() + " has " + person2.getAmount());
        }
    }
}

Copy after login

Problems with the current implementation:

  1. Repetitive code: The processPayment method logic is repeated for every payment method.
  2. Tightly coupled code: The application needs to create the payment method objects itself, making it hard to extend the application.
  3. Scalability issues: If new payment methods are added, the source code becomes more complex and harder to maintain.

Solution

The solution to the above situation is to use factory method pattern. So, how do we apply it ?

In the example above:

  1. Each if-else block calls the processPayment method, which leads to repetitive code.
  2. Objects are created based on the payment type condition, making the code messy with excessive if-else statements.

To solve these issues, the Factory Method pattern will be implemented step by step.

Folder structure (solution):

solution/
├─ BankApp.java
├─ service/
│  ├─ payments/
│  │  ├─ Payment.java
│  │  ├─ PaymentFactory.java
│  │  ├─ BankTransferPayment.java
│  │  ├─ PaypalTransferPayment.java
├─ data/
│  ├─ Person.java
Copy after login

Step 1: Create Payment interface, declares common method processPayment

package solution.service.payments;

import solution.data.Person;

// Step 1: Create an interface for the payment
public interface Payment {
    void processPayment(Person fromAccount, Person toAccount,float amount);
}
Copy after login

Step 2: Create BankTransferPayment and PaypalTransferPayment classes implement Payment interface.

package solution.service.payments;

import solution.data.Person;

// Step 2: Create a class that implements the Payment interface
public class BankTransferPayment implements Payment {
    @Override
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Bank transfer payment success.");
    }
}
Copy after login
package solution.service.payments;

import solution.data.Person;

public class PaypalPayment implements Payment{
    @Override
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Paypal transfer payment success.");
    }
}
Copy after login

Step 3: Create PaymentFactory class. This class is responsible for creating objects based on payment type condition.

package solution.service.payments;

public class PaymentFactory {
    public Payment createPayment(String paymentType) {
        if (paymentType == null) {
            return null;
        }
        if (paymentType.equalsIgnoreCase("BANK_TRANSFER")) {
            return new BankTransferPayment();
        } else if (paymentType.equalsIgnoreCase("PAYPAL")) {
            return new PaypalPayment();
        }
        return null;
    }
}
Copy after login

Step 4: Use the Factory in the Main Application.

Modify the main function to use the Factory Method pattern.

problem/
├─ BankApp.java
├─ service/
│  ├─ PaypalTransferPayment.java
│  ├─ BankTransferPayment.java
├─ data/
│  ├─ Person.java
Copy after login
Copy after login

Benefits of Using the Factory Method Pattern

  • The code is cleaner and more structured.
  • Repetitive calls to processPayment in multiple if-else blocks are eliminated.
  • Object creation is delegated to the factory, improving maintainability.

Bonus

To make the PaymentFactory class comply with the Open/Closed Principle (from SOLID principles), you can implement a dynamic registration mechanism using the Strategy Pattern.

Updated PaymentFactory.java:

package problem;

import problem.data.Person;

public class BankApp {
    public static void main(String[] args) {
        Person person1 = new Person("John", 1000);
        Person person2 = new Person("Jane", 500);
    }
}
Copy after login
Copy after login

Using the Updated Factory in the Main Application.

package problem.service;

import problem.data.Person;

public class BankTransferPayment {
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Bank transfer payment success.");
    }
}
Copy after login
Copy after login

By applying this approach, the code adheres to the Open/Closed Principle, enabling the addition of new payment methods without modifying the PaymentFactory logic.

I hope this post will be helpful to you.

References:

guru-design-patterns

The above is the detailed content of Understanding the Factory Method Pattern. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template