| title | Factory Pattern 🏭 |
|---|---|
| description | Introduction to Factory Pattern |
The Factory Pattern is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. It's used when we have a superclass with multiple subclasses and based on input, we need to return one of the subclasses.
- Product: An interface or abstract class defining the common interface of objects the factory method creates.
- Concrete Products: Classes that implement the Product interface.
- Creator: An abstract class that declares the factory method.
- Concrete Creator: A class that implements the factory method to create Concrete Product objects.
- The client calls the factory method with certain parameters.
- The factory method creates and returns the appropriate object based on those parameters.
- The client uses the object without knowing its specific class.
Here's a JavaScript example demonstrating the Factory Pattern:
// Product interface
class Vehicle {
constructor(model) {
this.model = model
}
getDetails() {
throw new Error("Method 'getDetails()' must be implemented.")
}
}
// Concrete Products
class Car extends Vehicle {
getDetails() {
return `Car: ${this.model}`
}
}
class Motorcycle extends Vehicle {
getDetails() {
return `Motorcycle: ${this.model}`
}
}
class Truck extends Vehicle {
getDetails() {
return `Truck: ${this.model}`
}
}
// Factory
class VehicleFactory {
createVehicle(type, model) {
switch (type.toLowerCase()) {
case "car":
return new Car(model)
case "motorcycle":
return new Motorcycle(model)
case "truck":
return new Truck(model)
default:
throw new Error("Unknown vehicle type.")
}
}
}
// Usage
const factory = new VehicleFactory()
const car = factory.createVehicle("car", "Tesla Model S")
const motorcycle = factory.createVehicle("motorcycle", "Honda Vision")
const truck = factory.createVehicle("truck", "Ford F-150")
console.log(car.getDetails())
console.log(motorcycle.getDetails())
console.log(truck.getDetails())
// Trying to create an unknown vehicle type
try {
const unknown = factory.createVehicle("boat", "Yacht")
} catch (error) {
console.error(error.message)
}Output:
> "Car: Tesla Model S"
> "Motorcycle: Honda Vision"
> "Truck: Ford F-150"
> "Unknown vehicle type"
In this example, we have a Vehicle interface and three concrete classes (Car, Motorcycle, and Truck) that implement it. The VehicleFactory class has a createVehicle method that returns the appropriate object based on the input type.
- When you don't know ahead of time what class object you need.
- When you want to centralize the logic of object creation.
- When you want to provide a library of products and only reveal their interfaces, not their implementations.
- Encapsulation: The Factory Pattern encapsulates object creation logic, making it easier to manage and modify.
- Flexibility: It's easy to introduce new types of products without changing existing code.
- Separation of Concerns: It separates the code that creates objects from the code that uses them.
- Loose Coupling: The client code isn't tightly coupled to specific classes, only to the interface.
- Complexity: It can introduce unnecessary complexity for simple object creation scenarios.
- Increased Number of Classes: The pattern often requires creating many new subclasses, which can bloat the codebase.
- Difficulty in Subclassing: Extending factories can be challenging if they have many factory methods.
- Use meaningful and consistent naming conventions for your factory methods.
- Consider using static factory methods for simpler scenarios.
- Use abstract factories when you have families of related products.
- Implement proper error handling for unknown product types.
- Abstract Factory: Provides an interface for creating families of related or dependent objects.
- Builder: Focuses on constructing complex objects step by step.
- Prototype: Creates new objects by copying an existing object, known as the prototype.
The Factory Pattern is a powerful tool in object-oriented design, offering flexibility and maintainability in object creation. While it's not suitable for every scenario, understanding when and how to use it can significantly improve your software design skills.
- Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. - Addison-Wesley.
- Freeman, E., Robson, E., Bates, B., & Sierra, K. (2004). Head First Design Patterns. - O'Reilly Media.
- Osmani, A. (2017). Learning JavaScript Design Patterns. - O'Reilly Media.