d9e5668cec
Fixes and improvements from exhaustive audit: Consistency fixes in SKILL.md: - 'Pipe & Filter' → 'Pipe and Filter' (one stray '&' found and corrected) - 'Singleton for factory instance' → clarified to 'register factory as singleton-scoped via DI container' (less misleading wording) - Documentation Format section updated with note that SKILL.md itself is the authoritative source for related-pattern combinations Coverage fix — Related Patterns sections: - Added '## Related Patterns' to ALL 94 pattern files (was 0/94) - Each section lists 3–6 related patterns with relationship descriptions - Covers: why they're related, when to prefer one vs the other, and which are often confused SOLID principles → Creational → Structural → Behavioral → Architectural → Concurrency → Functional → Resilience → Data Access → Messaging → Testing → Error Handling → Microservice — all 13 categories covered Code verification: - Python: 0 failures (all 85 testable blocks pass) - Go: 0 failures (all 76 testable blocks pass) - JavaScript: 0 failures (all 78 testable blocks pass) - All 239 code blocks verified correct after edits Final skill state: - 108 files, 36,524 lines across 13 reference categories - 94/94 pattern files have Related Patterns sections - 2,815-line SKILL.md with 67 decision trees, 23 scenarios, 0 broken references, 0 naming inconsistencies
8.3 KiB
8.3 KiB
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
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
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
// --- 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.