Factory

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

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

javascript
	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.