We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
System Design Masterclass · Microservices Architecture
Free preview: the first 2 parts of this 8-part lesson.
Already bought the course? Sign in to read the whole lesson.
this lesson is part of
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design courseread the rest of this lesson in
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design coursein Microservices Architecture
This lesson is part of the full System Design Masterclass. Unlock it along with 769 other lessons for a one-time payment.
One-time payment by card or PayPal
Get Lifetime AccessOne-time payment: UPI, card or netbanking
Get Lifetime Access18 Foundation lessons are free, no payment needed. Try them now
It is easy and good
“It is really nice and good Please join the course”
A startup in Bangalore had hardcoded Razorpay everywhere. new RazorpayClient() appeared in 47 files across their codebase. When they needed to add Stripe for international customers, they realized every single file that created a payment client needed to change. Not just the payment logic, the creation logic was scattered everywhere.
Three months of refactoring. Dozens of bugs. All because they'd tightly coupled "I need a payment processor" with "give me specifically a Razorpay instance."
The Factory pattern exists to prevent exactly this. Instead of code knowing which class to instantiate, it asks a factory: "give me a payment processor." The factory decides which concrete class to create based on context, region, configuration, feature flags, whatever. The calling code never knows and never cares.
The Factory pattern is about separating what you need from how it's created.
Without a factory, your code says: "I need a PostgresDatabase." That's a direct dependency on a concrete class.
With a factory, your code says: "I need a Database." The factory figures out whether that means Postgres, MySQL, SQLite, or an in-memory mock based on some configuration or context.
Here's why this matters in practice:
| Scenario | Without Factory | With Factory |
|---|---|---|
| Switch payment provider | Change 47 files | Change 1 factory method |
| Add a new database type | Modify every file that creates DB connections | Add one new case in the factory |
| Use mock in tests | Can't easily swap implementations | Factory returns mock in test mode |
| A/B test between implementations | Conditional logic everywhere | Factory reads feature flag, returns correct impl |
Three things get called a "factory", and it helps to keep them apart:
PaymentFactory.create(region) with a switch on region. Refactoring Guru, citing Head First Design Patterns, describes it as "a class that has one creation method with a large conditional that based on method parameters chooses which product class to instantiate and then return." It is not one of the Gang of Four patterns, but it is the one you will write most often in backend code.The payment example in this lesson is a simple factory. A Factory Method version would have a CheckoutFlow base class with an abstract createPaymentClient(), and an IndiaCheckoutFlow subclass that returns a Razorpay client while a USCheckoutFlow subclass returns a Stripe client. Both shapes hide the concrete class from the caller. The difference is where the decision lives: in one conditional, or spread across subclasses.