Design patterns are incredibly useful and one of the best programming practices followed by software developers. They provide solutions to those problems that are recurrent during software development. They’re also known as GoF (Gang of Four) Design Patterns, which are divided into three software design patterns: creational, behavioral, and structural. We’ll discuss one of the creational patterns called the factory pattern.
The factory pattern provides us with a superclass where we create objects of the classes, and the subclasses maintain the implementation part. We simply create a factory wrapper class that holds multiple classes, and then the object’s class is determined at runtime in the factory class. This way, the factory pattern allows us to decouple object creation from implementation, and we create objects by calling the factory method instead of the constructor.
Consider a scenario where we have three types of vehicles: Car, Truck, and Bicycle. Each vehicle class is encapsulated in a separate module. We’ll create a factory wrapper class to create instances of these vehicles at runtime.
Let’s dig into the details step by step:
Create a default Vehicle
class that provides us with the interface.
export class Vehicle {constructor (type) {this.type = type}}
Now, create modules for three types of vehicles that will import
the Vehicle
class.
Create a module for the Car
type:
import { Vehicle } from './vehicle.js'export class Car extends Vehicle {constructor (type) {super(type)}}
Create a module for the Truck
type:
import { Vehicle } from './vehicle.js'export class Truck extends Vehicle {constructor (type) {super(type)}}
Create a module for the Bicycle
type:
import { Vehicle } from './vehicle.js'export class Bicycle extends Vehicle {constructor (type) {super(type)}}
This module contains our factory wrapper class called VehicleFactory
.
import { Car } from './car.js'import { Truck } from './truck.js'import { Bicycle } from './bicycle.js'function VehicleFactory (type) {if (type.match(/\.jpe?g$/)) {return new ImageJpeg(type)} else if (type.match(/\.gif$/)) {return new ImageGif(type)} else if (type.match(/\.png$/)) {return new ImagePng(type)} else {throw new Error('Unsupported type of vehicle')}}const vehicle1 = VehicleFactory('car')const vehicle2 = VehicleFactory('truck')const vehicle3 = VehicleFactory('bicycle')console.log(vehicle1, vehicle2, vehicle3)
As we can see, the VehicleFactory
factory method handles the object creation of all the classes. This helps us keep the classes hidden and prevents them from being extended or modified.
Here’s the complete implementation of the code:
import { Vehicle } from './vehicle.js'export class Bicycle extends Vehicle {constructor (type) {super(type)}}
The factory pattern helps to simplify code by exposing just a small surface area, to maintain encapsulation and to decouple object creation. These things make this pattern very useful for developers to write code that’s clean and resilient.
Free Resources