Factory Method Pattern
Introduction
The Factory Method pattern is a creational 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 especially useful when a class can’t anticipate the class of objects it needs to create or when it wants its subclasses to specify the objects it creates.
Purpose
- Delegates the responsibility of object instantiation to subclasses.
- Promotes loose coupling by eliminating the need to bind application-specific classes into the code.
Use Cases
- When the class is only supposed to know about the objects it creates, not how to create them.
- In frameworks or libraries where implementation details are expected to be extended by client code.
Advantages/Disadvantages
Advantages:
- Promotes loose coupling by reducing the dependency on concrete classes.
- Supports the Open/Closed Principle by allowing easy extension of new types.
Disadvantages:
- Can lead to complex code due to the introduction of several new subclasses.
- Requires a deeper understanding of the underlying design to correctly implement.
Implementation in JavaScript
class Creator {
// Factory method
factoryMethod() {
throw new Error('Factory method not implemented');
}
// Method that calls the factory method
create() {
const product = this.factoryMethod();
return product;
}
}
class ConcreteCreatorA extends Creator {
// Overriding the factory method
factoryMethod() {
return new ConcreteProductA();
}
}
class ConcreteProductA {
operation() {
return 'Result of ConcreteProductA';
}
}
// Usage
const creatorA = new ConcreteCreatorA();
const productA = creatorA.create();
console.log(productA.operation()); // "Result of ConcreteProductA"
Practical Example
class ButtonCreator {
// Abstract factory method
createButton() {
throw new Error('Abstract method not implemented');
}
}
class WindowsButtonCreator extends ButtonCreator {
createButton() {
return new WindowsButton();
}
}
class MacButtonCreator extends ButtonCreator {
createButton() {
return new MacButton();
}
}
class WindowsButton {
render() {
return 'Windows Button';
}
}
class MacButton {
render() {
return 'Mac Button';
}
}
// Usage
function renderUI(buttonCreator) {
const button = buttonCreator.createButton();
console.log(button.render());
}
renderUI(new WindowsButtonCreator()); // "Windows Button"
renderUI(new MacButtonCreator()); // "Mac Button"
In this practical example, we have a ButtonCreator
class with an abstract createButton
method. The WindowsButtonCreator
and MacButtonCreator
classes extend this and implement the createButton
method to return a platform-specific button. This demonstrates how the Factory Method can be used to create families of related or dependent objects.