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

1. Overview

The Factory Pattern is a creational design pattern (a pattern about how objects get created). It gives you one place that decides which type of object to build.

The repo code is a Simple Factory: one LogisticsFactory class with a static getLogistics method. Factory Method is the subclass version, where each subclass decides what to create.

In Simpler Terms

Do not call new inside your business logic (the code that does the real work). Let a Factory create the objects, so your service does not need to know which concrete classes exist.


2. Class Diagram

LogisticsService stays free of the concrete Road and Air classes. It asks LogisticsFactory for an object and uses it through the Logistics interface.

Loading diagram…

3. The "Bad" Design: Tight Coupling

In the original version, LogisticsService created the objects itself. It chose the class by comparing strings such as "Air" and "Road".

Identified Issues:

  • Tight Coupling: LogisticsService names Air and Road directly, so a change to either one can break it.
  • Violation of OCP: The Open/Closed Principle says you add features without editing working code. Adding a new mode (e.g., "Ship") means editing the send method.
  • Mixed Concerns: One method both creates objects and does the business work.
  • Testing Nightmare: You cannot easily swap in a fake (mock) logistics object, so the service is hard to test alone.

4. The "Good" Design: Factory Implementation

Adding LogisticsFactory fixes these problems:

  • Loose Coupling: The service no longer knows the specific logistics classes.
  • SRP (Single Responsibility Principle): Each class has one job. Creating objects is now the factory's job.
  • Open/Closed Principle: You add new modes in the factory and leave the service code alone.

5. Pros and Cons

ProsCons
Loose Coupling: The client works with interfaces, not concrete classes.Complexity: Adds extra layers (interfaces/factories), which is too much for simple programs.
Extensibility: Adding new types (e.g., Drone, Ship) is easy.Boilerplate: You write more code up front.
Consistency: Creation logic sits in one place, so it is not copied around.Runtime Decisions: Choosing the type while the program runs can be a bit harder to manage.

6. When to Use

  • When the client code works with several types of objects.
  • When the program must pick the class at runtime (while it runs).
  • When creating the object is complex, or you want to control it in one place.

Comparison with your other learned patterns:

  • Builder: Builds a single complex object step by step (e.g., BurgerMeal).
  • Abstract Factory: Creates families of related objects (e.g., Payment + Invoice for a region).
  • Simple Factory (this note): Creates a single type of object and picks one of several implementations (e.g., a Logistics provider). Factory Method is its subclass version.

In this topic

Done with this topic?

How well do you know it?

PreviousSingleton Pattern Guide