Abstract Factory Design Pattern in JavaScript

1. Definition

The Abstract Factory Design Pattern is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.

2. Problem Statement

Consider developing a UI toolkit that needs to be consistent across multiple platforms like Web, Windows, and MacOS. While individual components like buttons, checkboxes, and windows can be created using the Factory Method pattern, managing these component sets for different platforms can become challenging.

3. Solution

The Abstract Factory pattern introduces an interface for creating all variants of product families. Subclasses implement this interface to produce objects that conform to the desired family of products.

4. Real-World Use Cases

1. A software suite that offers different themes (e.g., Dark Mode, Light Mode) where each theme provides its styled components.

2. Multi-platform game development where assets, controls, and physics might differ based on platform but need to remain consistent within each platform.

5. Implementation Steps

1. Declare abstract product interfaces for each type of product in the family.

2. Create concrete implementations for these product interfaces for each variant.

3. Define the abstract factory interface with methods for creating each product.

4. Implement a concrete factory for each product family variant.

6. Implementation in JavaScript

// Abstract Products
class Button {
  render() {}
}
class Checkbox {
  check() {}
}
// Concrete Products for Web
class WebButton extends Button {
  render() {
    return "Web Button";
  }
}
class WebCheckbox extends Checkbox {
  check() {
    return "Web Checkbox Checked";
  }
}
// Concrete Products for Windows
class WindowsButton extends Button {
  render() {
    return "Windows Button";
  }
}
class WindowsCheckbox extends Checkbox {
  check() {
    return "Windows Checkbox Checked";
  }
}
// Abstract Factory
class GUIFactory {
  createButton() {}
  createCheckbox() {}
}
// Concrete Factories
class WebFactory extends GUIFactory {
  createButton() {
    return new WebButton();
  }
  createCheckbox() {
    return new WebCheckbox();
  }
}
class WindowsFactory extends GUIFactory {
  createButton() {
    return new WindowsButton();
  }
  createCheckbox() {
    return new WindowsCheckbox();
  }
}
// Client code
function renderGUI(factory) {
  const button = factory.createButton();
  const checkbox = factory.createCheckbox();
  console.log(button.render());
  console.log(checkbox.check());
}
const webFactory = new WebFactory();
renderGUI(webFactory);
const windowsFactory = new WindowsFactory();
renderGUI(windowsFactory);

Output:

Web Button
Web Checkbox Checked
Windows Button
Windows Checkbox Checked

Explanation:

1. Button and Checkbox are abstract product interfaces.

2. WebButton, WebCheckbox, WindowsButton, and WindowsCheckbox are concrete implementations of these abstract products.

3. GUIFactory is the abstract factory interface with methods for creating buttons and checkboxes.

4. WebFactory and WindowsFactory are concrete factories implementing the GUIFactory interface, producing web and windows UI components respectively.

5. The client code uses these factories to render consistent UI components.

7. When to use?

Use the Abstract Factory pattern when:

1. The system needs to be independent of how its objects are created, composed, and represented.

2. The system is configured with multiple families of products.

3. Products from a family are designed to work together and you need to enforce this constraint.

4. You want to provide a library of products, and you want to reveal only their interfaces, not their implementations.


Comments