• Backend Weekly
  • Posts
  • Part 2: Factory and Abstract Factory Design Patterns (GoF)

Part 2: Factory and Abstract Factory Design Patterns (GoF)

In this episode, I will explore the Factory and Abstract Factory Patterns under the Creational Design Patterns.

In partnership with

Hello “👋”

Welcome to another week, another opportunity to become a Great Backend Engineer.

Today’s issue is brought to you by Masteringbackend → A great resource for backend engineers. We offer next-level backend engineering training and exclusive resources.

Before we get started, I have a few announcements:

We recently launched the first modules of three of our courses with a 44% discount for you.

Here are what to expect in each course.

  • 10+ in-depth modules

  • 50+ in-depth chapters

  • 160+ high-quality lessons

  • 48+ hours of video training content

Note that the discounted prices are going up every month as we add new modules.

Also, you can pick up a single course from a collection of courses we have on the MB Platform.

Check this out:

This cannabis startup pioneered “rapid onset” gummies

Most people prefer to smoke cannabis but that isn’t an option if you’re at work or in public.

That’s why we were so excited when we found out about Mood’s new Rapid Onset THC Gummies. They can take effect in as little as 5 minutes without the need for a lighter, lingering smells or any coughing.

Nobody will ever know you’re enjoying some THC.

We recommend you try them out because they offer a 100% money-back guarantee. And for a limited time, you can receive 20% off with code FIRST20.

Now, back to the business of today.

In this series, I will explain Design Patterns, their types, the GoF design patterns, drawbacks, and benefits for backend engineers.

This is coming from my new Vue.js book I’m writing on “Vue Design Patterns”. However, I’m only transferring the knowledge to backend engineers in this series.

Today, we will explore the Factory and Abstract Factory Patterns under the Creational Design Patterns.

Let’s get started quickly.

What are Factory Patterns?

The factory method is a design pattern under the creational design patterns that defines an interface for creating an object but lets subclasses alter the type of objects that will be created.

Here’s a real-world example:

Assuming you have an Animal class and within the Animal class you have many subclasses for different types of Animals.

For instance, you have subclasses for Dog, Cat, etc. You can use the Factory method to create the object of these subclasses within the Animal class.

Here’s a code example:

class Animal {}

class Dog extends Animal {}

class Cat extends Animal {}

class AnimalFactory {
    static create(type) {
        if (type === 'dog') {
            return new Dog();
        } else if (type === 'cat') {
            return new Cat();
        } else {
           throw new Error("Animal not recognized.");
        }
    }
}

// Usage
const dog = AnimalFactory.create('dog');
const cat = AnimalFactory.create('cat');

How is the factory method useful?

The Factory Method design pattern is useful because it provides a way to delegate the instantiation of objects to subclasses, promoting flexibility and scalability in the creation of objects without tightly coupling the client code to specific implementations.

Here’s why it’s beneficial:

Decouples Code from Concrete Classes

The Factory Method allows your code to depend on abstract classes or interfaces rather than specific classes. This is crucial in large systems because it reduces tight coupling.

When you need to add new object types, you don't need to modify existing code, ensuring the Open-Closed Principle (a class should be open for extension but closed for modification).

Example:

If you're building a logger, you might want to create different types of loggers (e.g., file logger, console logger, cloud logger). Using a factory method, the client doesn’t need to worry about what kind of logger is created, just that it will get a logger object.

class LoggerFactory {
    static create(dbType) {
        if (dbType === "console") {
            return new ConsoleLogger();
        } else if (dbType === "file") {
            return new FileLogger();
        } else {
            throw new Error("Unsupported logger");
        }
    }
}

class ConsoleLogger {
    log(message) {
        console.log(`Console log: ${message}`);
    }
}

class FileLogger {
    log(message) {
        // Code to log to a file
        console.log(`File log: ${message}`);
    }
}

// Client code
const logger = LoggerFactory.create('console');
logger.log("This is a log message.");

Why it’s useful: As you can see, the client only interacts with the LoggerFactory class.

If you decide to add a new type of logger in the future (like a cloud logger), you can do so without the client knowing the implementation.

Encapsulates Object Creation

The Factory Method encapsulates the object creation process, so clients don’t need to worry about the instantiation details. The factory hides the complexity behind the scenes and makes it easier to switch or extend the creation logic.

Example:

In the case of database connections, the client doesn’t need to know whether it’s connecting to MySQL, MongoDB, or Postgres. The factory method abstracts that away.

class DatabaseFactory {
    static create(dbType) {
        if (dbType === "MySQL") {
            return new MySQLConnection();
        } else if (dbType === "MongoDB") {
            return new MongoDBConnection();
        } else {
            throw new Error("Unsupported database");
        }
    }
}

class MySQLConnection {
    connect() {
        console.log("Connected to MySQL.");
    }
}

class MongoDBConnection {
    connect() {
        console.log("Connected to MongoDB.");
    }
}

// Client code
const dbConnection = DatabaseFactory.create("MySQL");
dbConnection.connect();

Why it’s useful: By encapsulating the logic of how connections are created, you can easily switch from MySQL to MongoDB without altering client code.

There are many other benefits to using the Factory method to instantiate your classes.

Here are a few summaries. The Factory Method is useful for:

  • Decoupling object creation from its usage.

  • Promoting flexibility and reusability.

  • Supporting the Open-Closed Principle.

  • Simplifying testing and extension.

It's especially handy when dealing with scenarios where you frequently need to instantiate different kinds of objects based on specific conditions or inputs.

Now, let’s move on to the Abstract Factory Method. However, if you have any questions regarding the Factory Method just shoot me an email.

Abstract Factory Patterns

Abstract factory patterns are similar to Factory patterns and provide the same benefits except that they provide an interface for creating families of related or dependent objects without specifying their concrete classes.

So in Abstract Factory Patterns, interfaces are used for creating related objects and not the concrete classes of these objects.

However, since JavaScript does not support interfaces directly, we can use a class the group related objects and extend the class.

Let’s take a look at Abstract Factory in action:

Assuming you want your users to create UI components depending on the mode like Dark or Light mode.

We can do it this way:

class UIFactory {
 createButton()
 createInput()
 ...
}

// Light theme Factory
class LightTheme extends UIFactory {
   createButton() {
    return new LightThemeButton();
  }

// implement other components here
}

// Dark theme Factory
class DarkTheme extends UIFactory {
   createButton() {
    return new DarkThemeButton();
  }
}

// Parent Button
class Button {}

// Child Button for Light theme
class LightThemeButton extends Button {
  constructor() {
    console.log('Light theme button created');
  }
}
 
// Child Button for Dark theme
class DarkThemeButton extends Button {
  constructor() {
    console.log('Dark theme button created');
  }
}



// Usage
const lightFactory = new LightThemeFactory();
const lightButton = lightFactory.createButton();
 
const darkFactory = new DarkThemeFactory();
const darkButton = darkFactory.createButton();

You can go ahead and add the code for Inputs.

From the code snippet above, you can see that we have a class called UIFactory which is supposed to be an Abstract class or an interface in other programming languages like Java with the following methods to be implemented.

Next, in each of the classes for each mode, we implemented the createButton function to return the different types of Buttons we want depending on the mode.

Next, each type of Button extends the parent Button and makes some modifications to suit the mode.

Lastly, we use the createButton function to create each type of button without knowing the deep implementation that happens.

Note that:

The Abstract Factory method and Factory method give almost the same benefits and they are all used to create objects. However, when you have a family of related or similar objects to create, then Abstract Factory Pattern works better.

For example, if you have to create the object for a Button, Input, Tooltip, Checkbox, etc for a Dark theme and a Button, Input, Tooltip, Checkbox, etc for a Light theme or something similar use Abstract Factory.

That will be all for today. I like to keep this newsletter short.

Today, I discussed the Factory Method and Abstract Factory Pattern, you learned how to implement them, their similarities, and when to use which.

Next week, I will start exploring the Builder Pattern.

Don’t miss it. Share with a friend

Did you learn any new things from this newsletter this week? Please reply to this email and let me know. Feedback like this encourages me to keep going.

See you on Next Week.

Remember to start learning backend engineering from our courses:

Top 5 Remote Backend Jobs this week

Here are the top 5 Backend Jobs you can apply to now.

👨‍💻 Binance
✍️ Backend Engineer - Java
đź“ŤRemote, Worldwide
đź’° Click on Apply for salary details
Click here to Apply for this role.

👨‍💻 Decaf
✍️ Senior Backend Developer
đź“ŤRemote, Worldwide
đź’° Click on Apply for salary details
Click here to Apply for this role.

👨‍💻 Pinterest
✍️ Backend Software Engineer
đź“ŤRemote, Worldwide
đź’° Click on Apply for salary details
Click here to Apply for this role.

👨‍💻Sportradar
✍️ Backend Engineer
đź“ŤRemote
đź’° Click on Apply for salary details
Click here to Apply for this role.

Want more Remote Backend Jobs? Visit GetBackendJobs.com

Backend Engineering Resources

Whenever you're ready

There are 4 ways I can help you become a great backend engineer:

1. The MB Platform: Join 1000+ backend engineers learning backend engineering on the MB platform. Build real-world backend projects, track your learnings and set schedules, learn from expert-vetted courses and roadmaps, and solve backend engineering tasks, exercises, and challenges.

2. ​The MB Academy:​ The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

3. MB Video-Based Courses: Join 1000+ backend engineers who learn from our meticulously crafted courses designed to empower you with the knowledge and skills you need to excel in backend development.

4. GetBackendJobs: Access 1000+ tailored backend engineering jobs, manage and track all your job applications, create a job streak, and never miss applying. Lastly, you can hire backend engineers anywhere in the world.

LAST WORD đź‘‹ 

How am I doing?

I love hearing from readers, and I'm always looking for feedback. How am I doing with The Backend Weekly? Is there anything you'd like to see more or less of? Which aspects of the newsletter do you enjoy the most?

Hit reply and say hello - I'd love to hear from you!

Stay awesome,
Solomon

I moved my newsletter from Substack to Beehiiv, and it's been an amazing journey. Start yours here.

Reply

or to participate.