# Factory Method

## Problem

You need to create objects of different types based on runtime conditions, but the calling
code shouldn't know or care about the concrete classes. Hard-coding `new ConcreteClass()`
scatters creation logic and makes the system rigid.

## Solution

Define a **creator method** that returns an interface/base type. Subclasses or conditional
logic inside the factory decide which concrete type to instantiate. The caller only works
with the abstract interface.

```
┌─────────────┐       ┌───────────┐
│ LoggerFactory│──────>│  Logger   │  (interface)
│  +create()   │       └─────┬─────┘
└─────────────┘             │
                    ┌───────┴───────┐
                    │               │
              ┌─────┴─────┐  ┌─────┴──────┐
              │ConsoleLogger│  │ FileLogger │
              └───────────┘  └────────────┘
```

## When to Use

- The exact type to create is determined at runtime (config, user input, environment).
- You want to isolate creation logic into one place.
- You need to return objects that share an interface but differ in implementation.

## When to Avoid

- Only one concrete type will ever exist — a factory adds needless indirection.
- You need to create **families** of related objects — use Abstract Factory instead.
- Object construction is complex with many steps — use Builder instead.

## Pseudocode

```
interface Logger:
    method log(message: string)

class ConsoleLogger implements Logger:
    method log(message):
        print("[CONSOLE] " + message)

class FileLogger implements Logger:
    method log(message):
        writeToFile("[FILE] " + message)

function createLogger(loggerType: string) -> Logger:
    if loggerType == "console":
        return new ConsoleLogger()
    else if loggerType == "file":
        return new FileLogger()
    else:
        throw UnknownLoggerError

// Usage
logger = createLogger("console")
logger.log("Application started")
```

## Python

```python
"""Factory Method — Logger example."""

from abc import ABC, abstractmethod


class Logger(ABC):
    """Abstract logger interface."""

    @abstractmethod
    def log(self, message: str) -> None: ...


class ConsoleLogger(Logger):
    def log(self, message: str) -> None:
        print(f"[CONSOLE] {message}")


class FileLogger(Logger):
    def __init__(self) -> None:
        self._buffer: list[str] = []

    def log(self, message: str) -> None:
        self._buffer.append(f"[FILE] {message}")
        print(f"[FILE] {message}")


class JsonLogger(Logger):
    def log(self, message: str) -> None:
        import json
        entry = json.dumps({"level": "info", "msg": message})
        print(f"[JSON] {entry}")


def create_logger(logger_type: str) -> Logger:
    """Factory function — the core of the pattern."""
    registry: dict[str, type[Logger]] = {
        "console": ConsoleLogger,
        "file": FileLogger,
        "json": JsonLogger,
    }
    cls = registry.get(logger_type)
    if cls is None:
        raise ValueError(f"Unknown logger type: {logger_type}")
    return cls()


if __name__ == "__main__":
    for kind in ("console", "file", "json"):
        logger = create_logger(kind)
        logger.log(f"Application started (via {kind})")
    print("--- Factory method demo complete ---")
```

## Go

```go
// factory.go — Factory Method: Logger example
package main

import (
	"encoding/json"
	"fmt"
)

// Logger is the product interface.
type Logger interface {
	Log(message string)
}

// ConsoleLogger prints to stdout.
type ConsoleLogger struct{}

func (c *ConsoleLogger) Log(message string) {
	fmt.Printf("[CONSOLE] %s\n", message)
}

// FileLogger simulates writing to a file.
type FileLogger struct {
	Buffer []string
}

func (f *FileLogger) Log(message string) {
	entry := fmt.Sprintf("[FILE] %s", message)
	f.Buffer = append(f.Buffer, entry)
	fmt.Println(entry)
}

// JSONLogger outputs structured JSON.
type JSONLogger struct{}

func (j *JSONLogger) Log(message string) {
	data, _ := json.Marshal(map[string]string{"level": "info", "msg": message})
	fmt.Printf("[JSON] %s\n", string(data))
}

// CreateLogger is the factory function.
func CreateLogger(loggerType string) (Logger, error) {
	switch loggerType {
	case "console":
		return &ConsoleLogger{}, nil
	case "file":
		return &FileLogger{}, nil
	case "json":
		return &JSONLogger{}, nil
	default:
		return nil, fmt.Errorf("unknown logger type: %s", loggerType)
	}
}

func main() {
	for _, kind := range []string{"console", "file", "json"} {
		logger, err := CreateLogger(kind)
		if err != nil {
			fmt.Println("Error:", err)
			continue
		}
		logger.Log(fmt.Sprintf("Application started (via %s)", kind))
	}
	fmt.Println("--- Factory method demo complete ---")
}
```

## JavaScript

```javascript
// factory.js — Factory Method: Logger example

class ConsoleLogger {
  log(message) {
    console.log(`[CONSOLE] ${message}`);
  }
}

class FileLogger {
  constructor() {
    this.buffer = [];
  }
  log(message) {
    const entry = `[FILE] ${message}`;
    this.buffer.push(entry);
    console.log(entry);
  }
}

class JsonLogger {
  log(message) {
    const entry = JSON.stringify({ level: "info", msg: message });
    console.log(`[JSON] ${entry}`);
  }
}

function createLogger(type) {
  const registry = {
    console: ConsoleLogger,
    file: FileLogger,
    json: JsonLogger,
  };
  const Cls = registry[type];
  if (!Cls) throw new Error(`Unknown logger type: ${type}`);
  return new Cls();
}

// --- Demo ---
for (const kind of ["console", "file", "json"]) {
  const logger = createLogger(kind);
  logger.log(`Application started (via ${kind})`);
}
console.log("--- Factory method demo complete ---");
```

## Related Patterns

- **Abstract Factory** — Factory Method creates one type; Abstract Factory creates families of related types. Abstract Factory uses Factory Methods internally.
- **Builder** — Both create objects. Factory Method creates in one step; Builder creates incrementally through multiple steps.
- **Prototype** — Alternative creation strategy: instead of a factory creating from scratch, Prototype clones an existing instance.
- **Strategy** — The factory often selects a Strategy to inject into the created object.
- **Dependency Injection** — DI containers use Factory Method internally to instantiate and wire dependencies.
