Fundamentals 16 min read

Factory Method Pattern: Deciding Which Variant to Create

This article walks through the evolution from direct object instantiation to Simple Factory and finally to the Factory Method pattern, explaining why scattering new statements is problematic, how Simple Factory centralizes creation but still violates the Open/Closed principle, and how the Factory Method delegates the decision to specialized factories, complete with code examples, role definitions, and guidance on when to apply each approach.

Dabaoshi
Dabaoshi
Dabaoshi
Factory Method Pattern: Deciding Which Variant to Create

From Scattered if‑else to Centralized Creation

The payment example shows if (payType.equals("wechat")) … else if ("alipay") … logic scattered throughout OrderService, coupling the service to concrete payment classes. Each new channel forces a new new and additional if‑else branches, mixing creation and business logic.

Simple Factory: Gather All new Calls

A PaymentFactory with a static create(String payType) method centralizes the switch statement. OrderService now only depends on the Payment interface and the factory, removing direct knowledge of concrete classes.

public class PaymentFactory {
    public static Payment create(String payType) {
        switch (payType) {
            case "wechat": return new WechatPayment();
            case "alipay": return new AlipayPayment();
            case "unionpay": return new UnionPayment();
            default: throw new IllegalArgumentException("Unsupported pay type: " + payType);
        }
    }
}

public class OrderService {
    public void pay(String payType, double amount) {
        Payment payment = PaymentFactory.create(payType);
        payment.pay(amount);
    }
}

While this removes scattered new calls, the factory still violates the Open/Closed principle because every new payment type requires modifying the switch.

Factory Method: Delegate Creation to Sub‑Factories

The Factory Method introduces an abstract factory interface PaymentFactory with a create() method. Each concrete payment gets its own factory implementation, e.g., WechatPaymentFactory, which returns a WechatPayment. OrderService now depends only on the factory interface and receives a concrete factory via constructor injection.

public interface PaymentFactory { Payment create(); }

public class WechatPaymentFactory implements PaymentFactory {
    public Payment create() { return new WechatPayment(); }
}

public class OrderService {
    private final PaymentFactory factory;
    public OrderService(PaymentFactory factory) { this.factory = factory; }
    public void pay(double amount) {
        Payment payment = factory.create();
        payment.pay(amount);
    }
}

// Usage
new OrderService(new WechatPaymentFactory()); // pays with WeChat
new OrderService(new AlipayPaymentFactory()); // pays with Alipay

Adding a new payment (e.g., Digital Currency) now only requires a new DcepPayment class and a corresponding DcepPaymentFactory, leaving existing code untouched—fulfilling the Open/Closed principle.

Four Roles in the Factory Method

Abstract Product : Payment interface defining common behavior.

Concrete Product : Classes like WechatPayment, AlipayPayment that implement Payment.

Creator (Abstract Factory) : PaymentFactory interface declaring create().

Concrete Creator : Specific factories such as WechatPaymentFactory that implement create() to instantiate their product.

The structure forms two parallel inheritance hierarchies—products on one side, factories on the other—so each concrete factory pairs with exactly one concrete product.

A common variant is to make the abstract factory an abstract class that provides shared logic (e.g., logging, validation) while subclasses only implement the actual object creation.

When Is a Factory Worth Using?

Do nothing (direct new ) : Only one implementation and simple construction.

Simple Factory : Multiple implementations, creation logic can be centralized, but adding a new product requires changing the switch.

Factory Method : Product set changes frequently or creation is complex; adding a product adds a new factory class without touching existing code.

The decision flow is: first ask if the object has multiple implementations; if yes, ask whether the set of implementations will grow often. Only when both answers are affirmative does the Factory Method pay off.

Real‑World Appearances and Boundaries

Collection.iterator()

– textbook Factory Method: Collection is the creator, iterator() the factory method, and concrete iterator classes are the products. Calendar.getInstance() – static Simple Factory returning locale‑specific subclasses.

Logging frameworks ( LoggerFactory.getLogger()) and Spring’s BeanFactory – both embody the “create‑and‑manage via a dedicated factory” idea.

Key distinctions:

Factory Method vs. Abstract Factory : The former creates a single product type; the latter creates families of related products.

Factory Method vs. Builder : Factory Method selects *which* product to create; Builder assembles a complex product step‑by‑step.

Summary

Creating objects directly couples business code to concrete classes. Simple Factory centralizes creation but still forces code changes for new variants, violating the Open/Closed principle. The Factory Method solves this by delegating the decision to specialized factories, achieving true extensibility at the cost of more classes. Use it only when multiple implementations exist and the set is expected to grow frequently; otherwise, Simple Factory or direct instantiation may be more appropriate.

Factory Method structure diagram
Factory Method structure diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSoftware DesignObject CreationDesign PatternSOLIDFactory Method
Dabaoshi
Written by

Dabaoshi

Practical utilities

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.