Design Patterns
Factory Pattern
Master the Factory Pattern in JavaScript. Learn to instantiate objects using creator classes, abstract configurations, and dynamic factory structures.
1. Introduction
The Factory Pattern is a creational design pattern that uses a factory function or creator class to instantiate objects, rather than calling class constructors using the new keyword directly.
2. Why It Matters
Instantiating classes using the new keyword directly couples your application to those specific classes. The Factory pattern decouples this process, allowing you to return different object instances dynamically based on configuration settings or environment variables.
3. Real-World Analogy
Think of a Automated Drink Dispenser (Factory):
- Direct Constructor instantiation: Walking to the warehouse, fetching a plastic cup, picking up syrup, mixing it with carbonated water, and assembling the drink yourself. You must manage the preparation steps.
- Factory Dispenser: You stand in front of a machine. You press a button: "Soda" or "Juice" (arguments). The machine handles the cups, mixing, and carbonation, and delivers the finished drink. You don't need to know how the drink is mixed to enjoy it.
4. Implementing the Factory
You can implement a Factory using a creator class that returns different class instances based on a configuration key:
5. Factory Function (FP Pattern)
In Functional Programming, you can implement a Factory using a simple function that returns an object, avoiding classes and the new keyword entirely:
6. Practical Example
This script demonstrates a log transporter factory that returns different log transporter instances based on environment settings:
7. Common Mistakes
- Overusing the Factory pattern for simple classes: If a class constructor is simple and does not require complex initialization logic or conditional instantiation, using a factory class adds unnecessary boilerplate code. Use the standard
newconstructor instead.
8. Quick Quiz
Q1: What is the primary benefit of using a Factory function instead of instantiating classes directly?
A) It compiles code into native binary streams
B) It decouples object instantiation, allowing you to return different object instances dynamically
Answer: B — The Factory pattern decouples object instantiation, allowing you to return different object instances dynamically based on settings or variables.
9. Scenario-Based Challenge
The Multi-Format Document Exporter:
An editor application allows users to export documents in PDF, CSV, or HTML formats. Design an exporter factory: ExporterFactory that returns the correct exporter instance (e.g. PDFExporter or CSVExporter) matching the format key dynamically.
10. Debugging Exercise
Explain why this factory function causes memory bloat when instantiating 1,000 objects, and how to fix it:
function createCircle(radius) {
return {
radius,
// Bug: method is declared inside the function body!
getArea() {
return Math.PI * this.radius * this.radius;
}
};
}
View Solution
Diagnosis: Declaring methods inside the factory function body creates a new function instance in memory for every returned object. Instantiating 1,000 objects creates 1,000 duplicate function instances, causing memory bloat.
Fix: Store methods on a shared prototype object or use a class constructor instead, ensuring that only a single function instance is shared across all objects:
const circleMethods = { getArea() { return Math.PI * this.radius * this.radius; } };
function createCircle(radius) { const circle = Object.create(circleMethods); // Inherit shared methods circle.radius = radius; return circle; }
11. Interview Questions
🟢 Q1: Explain how the Factory Pattern promotes the Dependency Inversion Principle.
Answer: The Dependency Inversion Principle states that high-level modules should not depend on low-level modules; both should depend on abstractions.
By using the Factory pattern to instantiate objects, the calling code only depends on the factory method interface and the abstract type it returns, rather than the specific low-level class constructors. This allows you to swap or modify low-level class definitions without changing the calling code.
12. Production Considerations
- • Factory over Constructor: Use a factory function when object instantiation requires complex logic (like parsing arguments, loading configurations, or selecting different classes) that doesn't fit cleanly inside a standard class constructor.