A few years ago, I worked on a growing application that started small but expanded faster than we expected.
Each new feature introduced a new way to create objects - notifications, reports, services - and every time, we added another if-else block.
At first, it was fine.
Then one day, a minor change broke three modules because a single creation method was edited in multiple files.
That's when I realized the problem wasn't in the logic - it was in the design.
We weren't managing object creation; we were repeating it.
That's when I discovered design patterns.
Why Design Patterns?
As applications evolve, developers often face the same structural problems repeatedly.
How do you create objects without duplicating logic?
How do you extend functionality without breaking existing code?
Instead of solving these problems from scratch every time, developers started identifying and documenting reusable approaches.
That led to the Gang of Four (GoF) book - Design Patterns: Elements of Reusable Object-Oriented Software (1994).
A design pattern isn't a library or a framework.
It's a reusable way to think about recurring design challenges.
The Real Problem
Imagine you're building a notification service.
You start with a simple design:
if type == :email
Notification::Email.new
elsif type == :sms
Notification::Sms.new
else
Notification::Push.new
end
It works.
But as the system grows, more notification types appear - Slack, WhatsApp, internal alerts.
Each new type means another line, another edit, another potential mistake.
Your code is now doing two things:
Running business logic.
Deciding which class to create.
This is exactly the kind of problem the Factory Method Pattern solves.
What Is the Factory Method Pattern?
The Factory Method Pattern is a creational design pattern that provides an interface for creating objects without specifying their concrete classes.
In other words, you tell the system what you need, and it decides how to build it.
How It Works
Let's refactor the earlier example.
class NotificationFactory
def self.build(type)
klass_name = "Notifications::#{type.to_s.camelize}"
if Object.const_defined?(klass_name)
klass_name.constantize.new
else
raise "Unknown notification type: #{type}"
end
end
end
module Notification
class Email
def send_message
puts "Sending email..."
end
end
class Sms
def send_message
puts "Sending SMS..."
end
end
class Push
def send_message
puts "Sending push notification..."
end
end
end
# When you call
notification = NotificationFactory.build(:email)
notification.send_message
# Output: Sending email...
notification = NotificationFactory.build(:whatsapp)
notification.send_message
# Output: Unknown notification type: whatsapp
Now you have implemented a Factory Method pattern.
In the future, if a new type Slack is added,
You just define the class inside Notification- no change in the factory, no code broken.
Visual Flow
Here's how this example works conceptually:
This is the essence of the Factory Method Pattern -
The client doesn't care which class was created.
It just asks the factory, and the right object is returned.
How Major Frameworks Use It
The Factory Method Pattern is everywhere - even if you don't notice it.
Rails:
When you call validates :email, presence: true, Rails dynamically decides whether to use PresenceValidator, LengthValidator, or FormatValidator.
React:
React.createElement(type) determines which component to render at runtime.
When (and When Not) to Use the Factory Method Pattern
Before applying it, here's a quick decision framework to help you decide whether the Factory Method Pattern is the right choice.
Use the Factory Method Pattern when:
You have multiple related object types.
You expect to add more types in the future.
You want to centralize and simplify object creation logic.
Avoid it when:
The number of types is fixed and small.
Simplicity matters more than scalability.
Now you've seen how replacing scattered if-else statements with intentional creation logic brings clarity and structure.
You're not just improving readability - you're building for the future.
Till next time - build systems that grow, but never crumble.


Top comments (0)