Back to Design Patterns
Structural Pattern

Facade Pattern

Provide a simplified interface to a complex subsystem, making it easier to use without exposing its internal complexity.

Beginner Friendly9 min read

What is the Facade Pattern?

The Facade pattern is a structural design pattern that provides a simple, unified interface to a set of complex interfaces in a subsystem. It doesn't add new functionality — it makes an existing complex system easier to use by wrapping it with a clean, high-level API.

Think of the ignition button in a modern car. Pressing it triggers fuel injection, spark ignition, sensor checks, ECU initialization, and more. You don't need to know any of that — the button is the facade that hides it all behind a single action.

In software, this is invaluable when working with complex libraries, layered architectures, or multi-service workflows where you want to provide a clean entry point for client code.

Key Idea: Wrap a complex subsystem with a simple, focused interface. The client talks to the facade; the facade coordinates the subsystem internally.

Core Participants

Facade

Facade

The simplified interface. Knows which subsystem classes handle which requests and delegates client calls to the appropriate subsystem objects. It can also do additional work like ordering operations and handling errors.

Subsystem Classes

Subsystem Classes

The complex underlying classes that do the real work. They have no knowledge of the facade — they operate independently and can be used directly by advanced clients who need fine-grained control.

Client

Client

Uses only the facade instead of calling subsystem classes directly. This shields it from all the complexity and makes it much easier to swap out or upgrade the subsystem.

!Problem It Solves

Complex Subsystem Exposure

Without Facade, every client must understand and coordinate all subsystem classes manually — in the right order, with the right arguments:

  • → Client code becomes tightly coupled to internal implementation details
  • → If the subsystem changes, every client must update
  • → Onboarding new developers requires deep knowledge of all subsystems
  • → Easy to call subsystem methods in the wrong order

Without Facade

// Client must know and coordinate everything — messy!
lights.dim(20);
projector.on();
projector.wideScreenMode();
sound.on();
sound.surroundSound();
sound.setVolume(60);
streaming.login();
dvd.on();
dvd.play(movie);  // 9 steps, easy to get wrong

With Facade

// Client calls one method — clean and safe
theatre.watchMovie("Interstellar");  // That's it!

How It Works

1

Identify the Subsystem

Group related classes that form a logical subsystem — e.g., all classes involved in placing an order.

2

Design the Facade API

Define the high-level operations a client would actually want to perform. Think "actions", not "steps".

3

Implement the Facade

The facade's methods coordinate subsystem calls internally — handling ordering, error handling, and data passing.

4

Client Uses Facade Only

Client code only imports and uses the facade class, remaining fully unaware of the underlying complexity.

Architecture

Client
Facade
simple API
Service A
Service B
Service C

Facade vs Adapter — Key Difference

AspectFacadeAdapter
GoalSimplify a complex systemMake incompatible interfaces work
InterfaceCreates a new, simpler interfaceConverts one existing interface to another
SubsystemWraps many classesTypically wraps one class
ProblemToo much complexityIncompatible API

Implementation

// Facade Pattern — Home Theatre System

// ─── Complex subsystem classes ────────────────────────────────
class DVDPlayer {
    public void on()           { System.out.println("[DVD] Player on"); }
    public void play(String m) { System.out.println("[DVD] Playing: " + m); }
    public void stop()         { System.out.println("[DVD] Stopped"); }
    public void off()          { System.out.println("[DVD] Player off"); }
}

class Projector {
    public void on()           { System.out.println("[Projector] On"); }
    public void wideScreenMode(){ System.out.println("[Projector] Widescreen mode"); }
    public void off()          { System.out.println("[Projector] Off"); }
}

class SoundSystem {
    public void on()           { System.out.println("[Sound] System on"); }
    public void setVolume(int v){ System.out.println("[Sound] Volume set to " + v); }
    public void surroundSound() { System.out.println("[Sound] Surround mode on"); }
    public void off()          { System.out.println("[Sound] System off"); }
}

class Lights {
    public void dim(int level) { System.out.println("[Lights] Dimmed to " + level + "%"); }
    public void on()           { System.out.println("[Lights] On"); }
}

class StreamingService {
    public void login()        { System.out.println("[Streaming] Logged in"); }
    public void search(String m){ System.out.println("[Streaming] Found: " + m); }
}

// ─── Facade ───────────────────────────────────────────────────
// Provides a single simple interface over the complex subsystem
class HomeTheatreFacade {
    private DVDPlayer      dvd;
    private Projector      projector;
    private SoundSystem    sound;
    private Lights         lights;
    private StreamingService streaming;

    public HomeTheatreFacade() {
        this.dvd       = new DVDPlayer();
        this.projector = new Projector();
        this.sound     = new SoundSystem();
        this.lights    = new Lights();
        this.streaming = new StreamingService();
    }

    // One method replaces 8+ manual steps
    public void watchMovie(String movie) {
        System.out.println("\n--- Getting ready to watch: " + movie + " ---");
        lights.dim(20);
        projector.on();
        projector.wideScreenMode();
        sound.on();
        sound.surroundSound();
        sound.setVolume(60);
        streaming.login();
        streaming.search(movie);
        dvd.on();
        dvd.play(movie);
    }

    public void endMovie() {
        System.out.println("\n--- Shutting down theatre ---");
        dvd.stop();
        dvd.off();
        sound.off();
        projector.off();
        lights.on();
    }
}

// ─── Client ───────────────────────────────────────────────────
public class Application {
    public static void main(String[] args) {
        HomeTheatreFacade theatre = new HomeTheatreFacade();

        // One call vs 10+ individual calls
        theatre.watchMovie("Interstellar");
        theatre.endMovie();
    }
}

When to Use Facade

Multi-Service Workflows

When a single user action (e.g., place order) requires coordinating multiple services — inventory, payment, shipping, notifications.

OrderFacade, CheckoutFacade

Third-Party Library Wrapping

When a library has dozens of classes and you only need a small slice of its functionality — wrap it in a facade.

EmailFacade, SmsFacade, MapFacade

Layered Architecture

In MVC or layered apps, service/facade layers expose clean methods to controllers, hiding repository and domain logic.

UserService, ProductService

SDK / API Design

When building a public SDK or library — expose a simple facade API and keep your internal implementation hidden and changeable.

PaymentSDK, AuthSDK

Legacy System Wrapping

When modernising a legacy codebase — wrap the old messy code with a clean facade while you gradually refactor internally.

LegacyOrderFacade, OldCRMFacade

Pros & Cons

Advantages

  • Isolates clients from subsystem complexity
  • Single entry point makes the codebase easier to navigate
  • Subsystem changes don't affect client code
  • Promotes loose coupling — client depends on facade only
  • Great for layered architectures and onboarding

Disadvantages

  • Facade can become a "god object" if not designed carefully
  • May hide functionality that power users actually need
  • Adds an extra layer — possible slight overhead
  • Risk of tight coupling if facade does too much logic itself

Real-World Examples

Spring's JdbcTemplate (Java)

JdbcTemplate is a facade over the complex JDBC API — it hides connection management, statement creation, exception handling, and result set closing behind simple query methods.

Django's ORM (Python)

Django's model QuerySet API is a facade — Model.objects.filter(...).order_by(...) hides SQL generation, connection pooling, and result mapping behind a clean Pythonic interface.

Axios / Fetch Wrappers (JavaScript)

Custom API service classes like apiService.getUser(id) are facades over fetch or Axios — they hide base URL configuration, auth headers, error handling, and response parsing.

AWS SDK High-Level Clients

AWS SDK offers both low-level and high-level clients. S3Transfer is a facade over raw S3 operations, handling multipart uploads, retries, and progress tracking automatically.

What's Next?

Now that you understand Facade, explore related Structural patterns: