# Facade Pattern

> Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

## Problem

A home theater system has many components — Projector, SoundSystem, Lights, MediaPlayer — each with its own API. Starting a movie requires calling multiple methods in the right order across several objects. Clients shouldn't need to know every subsystem detail.

## Solution

Create a `HomeTheater` facade that exposes simple operations like `watch_movie()` and `end_movie()`, internally orchestrating all the subsystem calls.

```
┌──────────┐
│  Client  │
└────┬─────┘
     │
     ▼
┌─────────────────┐
│   HomeTheater   │  ◄── Facade
│   (facade)      │
│ + watch_movie() │
│ + end_movie()   │
└──┬──┬──┬──┬─────┘
   │  │  │  │
   ▼  ▼  ▼  ▼
 Projector  SoundSystem  Lights  MediaPlayer
```

## When to Use

- You need a simple interface to a complex subsystem.
- There are many dependencies between clients and the implementation classes.
- You want to layer your subsystems and provide entry points to each layer.

## When to Avoid

- The subsystem is already simple enough that a facade adds no value.
- Clients genuinely need fine-grained control over subsystem components.
- The facade becomes a "god object" that does too much — split into multiple facades.

## Pseudocode

```
class Projector:
    method on():   output "Projector on"
    method off():  output "Projector off"

class SoundSystem:
    method on():         output "Sound on"
    method set_volume(v): output "Volume set to " + v
    method off():        output "Sound off"

class Lights:
    method dim(level):   output "Lights dimmed to " + level + "%"
    method on():         output "Lights on"

class MediaPlayer:
    method play(movie):  output "Playing: " + movie
    method stop():       output "Player stopped"

class HomeTheater:
    field projector, sound, lights, player

    constructor(projector, sound, lights, player):
        assign all fields

    method watch_movie(movie):
        output "=== Preparing to watch movie ==="
        lights.dim(10)
        projector.on()
        sound.on()
        sound.set_volume(8)
        player.play(movie)

    method end_movie():
        output "=== Shutting down ==="
        player.stop()
        sound.off()
        projector.off()
        lights.on()
```

## Python

```python
class Projector:
    def on(self) -> None:
        print("Projector on")

    def off(self) -> None:
        print("Projector off")


class SoundSystem:
    def on(self) -> None:
        print("Sound system on")

    def set_volume(self, level: int) -> None:
        print(f"Volume set to {level}")

    def off(self) -> None:
        print("Sound system off")


class Lights:
    def dim(self, percent: int) -> None:
        print(f"Lights dimmed to {percent}%")

    def on(self) -> None:
        print("Lights on full")


class MediaPlayer:
    def play(self, movie: str) -> None:
        print(f"Playing: {movie}")

    def stop(self) -> None:
        print("Player stopped")


class HomeTheater:
    """Facade that simplifies home theater operations."""

    def __init__(
        self,
        projector: Projector,
        sound: SoundSystem,
        lights: Lights,
        player: MediaPlayer,
    ) -> None:
        self._projector = projector
        self._sound = sound
        self._lights = lights
        self._player = player

    def watch_movie(self, movie: str) -> None:
        print("=== Preparing to watch movie ===")
        self._lights.dim(10)
        self._projector.on()
        self._sound.on()
        self._sound.set_volume(8)
        self._player.play(movie)
        print()

    def end_movie(self) -> None:
        print("=== Shutting down ===")
        self._player.stop()
        self._sound.off()
        self._projector.off()
        self._lights.on()


if __name__ == "__main__":
    theater = HomeTheater(
        projector=Projector(),
        sound=SoundSystem(),
        lights=Lights(),
        player=MediaPlayer(),
    )

    theater.watch_movie("The Matrix")
    theater.end_movie()
```

**Output:**
```
=== Preparing to watch movie ===
Lights dimmed to 10%
Projector on
Sound system on
Volume set to 8
Playing: The Matrix

=== Shutting down ===
Player stopped
Sound system off
Projector off
Lights on full
```

## Go

```go
package main

import "fmt"

// --- Subsystem components ---

type Projector struct{}

func (p *Projector) On()  { fmt.Println("Projector on") }
func (p *Projector) Off() { fmt.Println("Projector off") }

type SoundSystem struct{}

func (s *SoundSystem) On()              { fmt.Println("Sound system on") }
func (s *SoundSystem) SetVolume(v int)  { fmt.Printf("Volume set to %d\n", v) }
func (s *SoundSystem) Off()             { fmt.Println("Sound system off") }

type Lights struct{}

func (l *Lights) Dim(percent int) { fmt.Printf("Lights dimmed to %d%%\n", percent) }
func (l *Lights) On()             { fmt.Println("Lights on full") }

type MediaPlayer struct{}

func (m *MediaPlayer) Play(movie string) { fmt.Printf("Playing: %s\n", movie) }
func (m *MediaPlayer) Stop()             { fmt.Println("Player stopped") }

// --- Facade ---

type HomeTheater struct {
	projector *Projector
	sound     *SoundSystem
	lights    *Lights
	player    *MediaPlayer
}

func NewHomeTheater() *HomeTheater {
	return &HomeTheater{
		projector: &Projector{},
		sound:     &SoundSystem{},
		lights:    &Lights{},
		player:    &MediaPlayer{},
	}
}

func (h *HomeTheater) WatchMovie(movie string) {
	fmt.Println("=== Preparing to watch movie ===")
	h.lights.Dim(10)
	h.projector.On()
	h.sound.On()
	h.sound.SetVolume(8)
	h.player.Play(movie)
	fmt.Println()
}

func (h *HomeTheater) EndMovie() {
	fmt.Println("=== Shutting down ===")
	h.player.Stop()
	h.sound.Off()
	h.projector.Off()
	h.lights.On()
}

func main() {
	theater := NewHomeTheater()
	theater.WatchMovie("The Matrix")
	theater.EndMovie()
}
```

**Output:**
```
=== Preparing to watch movie ===
Lights dimmed to 10%
Projector on
Sound system on
Volume set to 8
Playing: The Matrix

=== Shutting down ===
Player stopped
Sound system off
Projector off
Lights on full
```

## JavaScript

```javascript
// --- Subsystem components ---

class Projector {
  on() {
    console.log("Projector on");
  }
  off() {
    console.log("Projector off");
  }
}

class SoundSystem {
  on() {
    console.log("Sound system on");
  }
  setVolume(level) {
    console.log(`Volume set to ${level}`);
  }
  off() {
    console.log("Sound system off");
  }
}

class Lights {
  dim(percent) {
    console.log(`Lights dimmed to ${percent}%`);
  }
  on() {
    console.log("Lights on full");
  }
}

class MediaPlayer {
  play(movie) {
    console.log(`Playing: ${movie}`);
  }
  stop() {
    console.log("Player stopped");
  }
}

// --- Facade ---

class HomeTheater {
  constructor() {
    this._projector = new Projector();
    this._sound = new SoundSystem();
    this._lights = new Lights();
    this._player = new MediaPlayer();
  }

  watchMovie(movie) {
    console.log("=== Preparing to watch movie ===");
    this._lights.dim(10);
    this._projector.on();
    this._sound.on();
    this._sound.setVolume(8);
    this._player.play(movie);
    console.log();
  }

  endMovie() {
    console.log("=== Shutting down ===");
    this._player.stop();
    this._sound.off();
    this._projector.off();
    this._lights.on();
  }
}

// --- Main ---
const theater = new HomeTheater();
theater.watchMovie("The Matrix");
theater.endMovie();
```

**Output:**
```
=== Preparing to watch movie ===
Lights dimmed to 10%
Projector on
Sound system on
Volume set to 8
Playing: The Matrix

=== Shutting down ===
Player stopped
Sound system off
Projector off
Lights on full
```

## Related Patterns

- **Adapter** — Both wrap complex things. Adapter makes incompatible interfaces compatible; Facade simplifies a complex subsystem without changing the interface.
- **Mediator** — Both simplify interactions. Facade is one-way (client to subsystem); Mediator is multi-directional (coordinates between subsystem components).
- **Service Layer** — Service Layer is an application-level Facade over the domain and data access layers.
- **Module** — Module is a code-organization Facade: it groups related functionality and exposes a clean public API.
