Abstract Factory includes several create methods to create related product types.

Create one product type? → Factory Method

Components

SOLID Principle

✅ Single Responsibility Principle (SRP)

✅ Open/Closed Principle (OCP): Abstract Factory allows to extend

✅ Liskov Substitution Principle (LSP) / Interface Segregation Principle (ISP): The Abstract Factory has a simple interface (create methods) letting Concrete Factories to implement. ⚠️ But the other extra common logics in abstract objects needs to be careful.

✅ Dependency Inversion Principle (DIP): Factories depend on Abstract Products.

Implementation

Inheritance

// Abstract Factory
abstract class GUIFactory {
	// Create methods
  public abstract createButton(): Button;
  public abstract createCheckbox(): Checkbox;
	
	// Reusable Shared Logic
  protected logFactoryUsage(): void {
    console.log(`[${this.constructor.name}] factory used.`);
  }
}

// Concrete Factories
// The product can either be encapsulated in the factory or use DI injection.
//  - Encapsulation: for fixed type cohesion and simplicity
//  - DI: for testability and runtime flexibility
class MacFactory extends GUIFactory {
  public createButton(): Button { return new MacButton(); }
  public createCheckbox(): Checkbox { return new MacCheckbox(); }
}
class WinFactory extends GUIFactory {
  public createButton(): Button { return new WinButton(); }
  public createCheckbox(): Checkbox { return new WinCheckbox(); }
}

// Abstract Products
interface Button {
  render(): void;
}
interface Checkbox {
  check(): void;
}

// Concrete Products
class MacButton implements Button {
  render() { console.log("Render Mac Button"); }
}
class WinButton implements Button {
  render() { console.log("Render Windows Button"); }
}
class MacCheckbox implements Checkbox {
  check() { console.log("Check Mac Checkbox"); }
}
class WinCheckbox implements Checkbox {
  check() { console.log("Check Windows Checkbox"); }
}

// Client
function compute(factory: GUIFactory) {
	const btn = factory.createButton();
  const checkbox = factory.createCheckbox();
	btn.render();
  checkbox.check();
}

compute(new MacFactory());
compute(new WinFactory());

Interface Polymorphism

// Abstract Factory
interface GUIFactory {
	// Create methods
  createButton(): Button;
  createCheckbox(): Checkbox;

  // Reusable Shared Logic
  logFactoryUsage(): void;
}

// Concrete Factories
// The product can either be encapsulated in the factory or use DI injection.
//  - Encapsulation: for fixed type cohesion and simplicity
//  - DI: for testability and runtime flexibility
class MacFactory implements GUIFactory {
  public createButton(): Button { return new MacButton(); }
  public createCheckbox(): Checkbox { return new MacCheckbox(); }
  private logFactoryUsage(): void { console.log("MacFactory factory used."); }
}

class WinFactory implements GUIFactory {
  public createButton(): Button { return new WinButton(); }
  public createCheckbox(): Checkbox { return new WinCheckbox(); }
  private logFactoryUsage(): void { console.log("WinFactory factory used."); }
}

// ... same code

Go Interface Polymorphism

Go lacks encapsulation mechanisms (private, protected, public).

// Abstract Factory
type GUIFactory interface {
	// Create methods
	CreateButton() Button
	CreateCheckbox() Checkbox
	// Reusable Shared Logic
	logFactoryUsage()
}

// Concrete Factories
// The product can either be encapsulated in the factory or use DI injection.
//  - Encapsulation: for fixed type cohesion and simplicity
//  - DI: for testability and runtime flexibility
type MacFactory struct{}
func (MacFactory) CreateButton() Button { return MacButton{} }
func (MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }
func (MacFactory) logFactoryUsage() { fmt.Println("MacFactory factory used.") }
type WinFactory struct{}
func (WinFactory) CreateButton() Button { return WinButton{} }
func (WinFactory) CreateCheckbox() Checkbox { return WinCheckbox{} }
func (MacFactory) logFactoryUsage() { fmt.Println("WinFactory factory used.") }

// Abstract Products
type Button interface {
	Render()
}
type Checkbox interface {
	Check()
}

// Concrete Products
type MacButton struct{}
func (MacButton) Render() { fmt.Println("Render Mac Button") }
type WinButton struct{}
func (WinButton) Render() { fmt.Println("Render Windows Button") }
type MacCheckbox struct{}
func (MacCheckbox) Check() { fmt.Println("Check Mac Checkbox") }
type WinCheckbox struct{}
func (WinCheckbox) Check() { fmt.Println("Check Windows Checkbox") }

// Client
func compute(factory GUIFactory) {
	btn := factory.createButton();
  checkbox := factory.createCheckbox();
	btn.render();
  checkbox.check();
}

func main() {
	compute(MacFactory{})
	compute(WinFactory{})
}