🧱 Structural

Facade Pattern

Provides a simplified interface to a library, framework, or complex subsystem. A facade doesn't encapsulate the subsystem; it just offers a convenient, higher-level interface that makes the subsystem easier to use while still allowing direct access when needed.

Problem

When your code must work with a large number of objects from a complex subsystem, you need to manage all those objects, keep track of their dependencies, initialize them in the correct order, and so on. The business logic of your classes becomes tightly coupled to the implementation details of the subsystem, making it hard to understand and maintain.

Solution

Create a facade class that provides a simple interface to the complex subsystem. The facade delegates client requests to appropriate subsystem objects. The facade manages the lifecycle and interaction of subsystem components, hiding that complexity from clients. Clients can still use subsystem classes directly if they need fine-grained control.

Participants

RoleResponsibility
FacadeProvides a simplified interface to the subsystem; delegates client requests to subsystem objects
Subsystem ClassesImplement subsystem functionality; handle work assigned by the Facade; have no knowledge of the Facade
ClientUses the Facade instead of calling subsystem objects directly

TypeScript Example

TypeScript
class FileReader {
  read(path: string) { return `raw data from ${path}`; }
}

class DataParser {
  parse(raw: string) { return { parsed: raw.toUpperCase() }; }
}

class Validator {
  validate(data: { parsed: string }) {
    return data.parsed.length > 0;
  }
}

class ReportGenerator {
  generate(data: { parsed: string }) {
    return `=== Report ===\n${data.parsed}\n==============`;
  }
}

class ReportFacade {
  private reader = new FileReader();
  private parser = new DataParser();
  private validator = new Validator();
  private generator = new ReportGenerator();

  generateReport(filePath: string): string {
    const raw = this.reader.read(filePath);
    const data = this.parser.parse(raw);
    if (!this.validator.validate(data)) {
      throw new Error("Invalid data");
    }
    return this.generator.generate(data);
  }
}

const facade = new ReportFacade();
console.log(facade.generateReport("sales-q4.csv"));

Real-World Example

When you order something online, you click a single 'Place Order' button. Behind the scenes, the system checks inventory, processes payment, generates an invoice, schedules shipping, and sends a confirmation email. The checkout button is the facade. In software, jQuery is a facade over the complex DOM API. Similarly, ORMs like Prisma provide a facade over raw SQL and database connection management.

When to Use

  • You want to provide a simple interface to a complex subsystem
  • You need to layer your subsystems and use a facade as an entry point to each level
  • You want to decouple clients from subsystem components to promote subsystem independence
  • You need to reduce the number of dependencies between the client and the subsystem

When Not to Use

  • The subsystem is already simple enough that a facade adds no value
  • Clients need fine-grained control that the facade doesn't expose
  • The facade becomes a god object trying to do too much

Understanding the Facade Pattern

The Facade pattern is one of the most important structural design patterns in object-oriented software design. Originally cataloged by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) in their seminal 1994 book "Design Patterns: Elements of Reusable Object-Oriented Software," this pattern continues to be a cornerstone of modern software architecture.

Provides a simplified interface to a library, framework, or complex subsystem. A facade doesn't encapsulate the subsystem; it just offers a convenient, higher-level interface that makes the subsystem easier to use while still allowing direct access when needed. The pattern involves the following key participants: Facade, Subsystem Classes, Client. Each participant has a well-defined role, and the interactions between them create a flexible, maintainable structure that can evolve with changing requirements.

In TypeScript and modern JavaScript development, the Facade pattern is particularly valuable because the language's type system and interface support allow you to express the pattern with compile-time safety. TypeScript generics can make Facade implementations even more flexible and reusable while maintaining strong type checking throughout the pattern's structure.

Knowing when to apply the Facade pattern is as important as knowing how. Common use cases include: You want to provide a simple interface to a complex subsystem; You need to layer your subsystems and use a facade as an entry point to each level; You want to decouple clients from subsystem components to promote subsystem independence. However, overusing design patterns can lead to unnecessarily complex code. Always evaluate whether the pattern genuinely solves your problem or if a simpler approach would suffice.

The Facade pattern is related to several other design patterns: Adapter, Mediator, Singleton, Abstract Factory. Understanding these relationships helps you choose the right pattern for your specific situation and combine patterns effectively when building complex systems.

Related Patterns

More Structural Patterns

Explore All Design Patterns

Browse our complete reference of 23 design patterns with TypeScript examples, UML participants, and practical guidance.