What?
The factory pattern is a creational design pattern used to create objects without specifying the exact class of object that will be created. Instead of calling a constructor directly, a factory method is called to create an object.
Prerequisites:
- Node.js and npm installed.
- Basic knowledge of NestJS
Let's explore this with a TypeScript example:
Suppose we have a scenario where we want to create different types of shapes.
First, define the base class and its derivatives:
interface Shape {
draw(): void;
}
class Circle implements Shape {
draw(): void {
console.log("Drawing a circle.");
}
}
class Square implements Shape {
draw(): void {
console.log("Drawing a square.");
}
}
class Triangle implements Shape {
draw(): void {
console.log("Drawing a triangle.");
}
}
Now, let's create the factory to produce objects of the above types:
class ShapeFactory {
createShape(type: string): Shape | null {
if (!type) {
return null;
}
switch (type.toLowerCase()) {
case "circle":
return new Circle();
case "square":
return new Square();
case "triangle":
return new Triangle();
default:
return null;
}
}
}
Now you can use the factory to create and use the shape objects:
const shapeFactory = new ShapeFactory();
const circle: Shape = shapeFactory.createShape("circle");
circle.draw();
const square: Shape = shapeFactory.createShape("square");
square.draw();
const triangle: Shape = shapeFactory.createShape("triangle");
triangle.draw();
Let me tell you
- We first defined an interface
Shape
with adraw
method. This represents the contract that all shapes must adhere to. - The
Circle
,Square
, andTriangle
classes implement the Shapeinterface
and provide concrete implementations for thedraw
method. - Instead of directly instantiating these
shape
objects, we use theShapeFactory
class to do this for us. - The factory has a
createShape
method which takes a type as a parameter and returns the respective object. - When we want a new shape object, we just call the
createShape
method on the factory with the desired type.
Benefits:
- The main benefit of the factory pattern is that it promotes loose coupling. The system remains independent of how its objects are created, composed, and represented.
- It provides a centralized location to manage and control object creation.
- It's easier to add new shapes in the future, by simply adding a new class that implements the Shape interface and updating the factory method.
Remember, the factory pattern is useful when:
- The exact type of the object is decided at runtime.
- There are families of related classes and only one family is supposed to be used at runtime.
- When you want to provide a library of objects and you want to expose just the methods for creating the objects, not the actual classes and constructors.