Skip to content

Design Pattern: Simple Factory (Creational)

Creating objects without naming the concrete class

Builds on Interfaces and OCP - The Open/Closed Principle

Stage 3core2 min read

The Factory Pattern Solution

The refactored code uses the Simple Factory Pattern. All object creation now happens in LogisticsFactory, so LogisticsService no longer depends on classes like Air or Road.


1. Key Improvements

Separation of Concerns

  • The Benefit: LogisticsService does not need to know how to create a transport object. It only needs to know how to use one.
  • The Result: Separate classes handle the business logic (sending) and the creation logic (building the object).

Encapsulation of "New"

  • The Benefit: Only the Factory uses the new keyword.
  • The Impact: If the Air constructor changes tomorrow, you fix it in one place (the Factory), not in every class that uses Air.

Error Handling & Validation

  • The Benefit: The Factory is one place to check the input.
  • The Safety: For an unknown mode, the Factory throws an IllegalArgumentException. The system never carries on with a missing (null) object.

2. Structural Breakdown

ComponentResponsibility
Product Interface (Logistics)Defines the shared methods every transport type must have.
Concrete Products (Air, Road)Real classes that implement the interface, each with its own logic.
Factory Class (LogisticsFactory)Decides which concrete product to create, based on the input.
Client (LogisticsService)Asks the factory for an object and uses it through the interface.

3. Comparison of "Before" vs "After"

FeatureBefore (Hardcoded)After (Factory Pattern)
DependencyDepends on Air and Road classes.Depends on Logistics interface.
MaintenanceHigh risk; adding a mode can break existing code.Low risk; changes are isolated to the Factory.
TestingHard to replace concrete objects with fakes (mocks).Easy to fake the interface in unit tests.
FlexibilityFixed if-else inside the service.One simple call that hands creation to a Factory.

In this topic

After code1 file

GoodCode/Main.java76 linesGitHub
package DesignPatterns.CreationalPatterns.FactoryDesignPattern.GoodCode;/** * 1. PRODUCT INTERFACE * Defines the common behavior for all transport types. */interface Logistics {    void send();}/** * 2. CONCRETE PRODUCTS * Specific implementations of the Logistics interface. */class Road implements Logistics {    @Override    public void send() {        System.out.println("Sending by road logic");    }}class Air implements Logistics {    @Override    public void send() {        System.out.println("Sending by air logic");    }}/** * 3. THE FACTORY * Encapsulates the 'new' keyword and instantiation logic. * This is the only place where the system decides which class to create. */class LogisticsFactory {    public static Logistics getLogistics(String mode) {        // Benefit: We can use ignoreCase to prevent common string typos        if (mode.equalsIgnoreCase("Air")) {            return new Air();        } else if (mode.equalsIgnoreCase("Road")) {            return new Road();        }        // Error Handling: Centralized place to handle invalid requests        throw new IllegalArgumentException("Unknown logistics mode: " + mode);    }}/** * 4. THE SERVICE (Client) * Now purely focused on THE USE of the object, not the CREATION. * It is decoupled from 'Air' and 'Road' classes. */class LogisticsService {    public void send(String mode) {        /* Dependency Inversion: The service depends on the Logistics interface,           not the concrete Air/Road implementations.        */        Logistics logistics = LogisticsFactory.getLogistics(mode);        logistics.send();    }}// Driver Codeclass Main {    public static void main(String[] args) {        LogisticsService service = new LogisticsService();        service.send("Air");        service.send("Road");    }}

Done with this topic?

How well do you know it?

PreviousSingleton Pattern Guide