Facade Pattern in TypeScript — ✨ Structural Design Pattern #4

365kim
3 min readJun 26, 2023

--

Photo by Norbert Levajsics on Unsplash

In software development, it’s not uncommon to encounter complex systems with numerous subsystems and interdependencies. Managing and interacting with such systems can become a daunting task. This is where the Facade Pattern comes to the rescue. The Facade Pattern provides a unified interface to a set of interfaces in a subsystem, simplifying the usage and understanding of the system as a whole.

🙋🏻‍♀️ What is the Facade Pattern?

The Facade Pattern is a structural design pattern that provides a simplified interface to a complex system, making it easier to use and understand. It acts as a high-level interface that hides the complexities of the underlying subsystem.

The main idea behind the Facade Pattern is to create a facade class that encapsulates the interactions with the subsystem’s components, shielding the client from the details of individual subsystem components and their interactions.

✨ Simple Example

Let’s consider an example of a home theater system. A home theater system consists of various components, such as a DVD player, a projector, a screen, and a sound system. To set up and control the home theater system, you have to control each component individually. However, with the Facade Pattern, we can create a simplified interface that hides the complexities of the individual components.

class DVDPlayer {
turnOn(): void {
console.log('DVD Player turned on');
}

playMovie(): void {
console.log('Movie playing');
}

turnOff(): void {
console.log('DVD Player turned off');
}
}

class Projector {
turnOn(): void {
console.log('Projector turned on');
}

setInput(input: string): void {
console.log(`Input set to ${input}`);
}

turnOff(): void {
console.log('Projector turned off');
}
}

class Screen {
up(): void {
console.log('Screen raised');
}

down(): void {
console.log('Screen lowered');
}
}

class SoundSystem {
turnOn(): void {
console.log('Sound System turned on');
}

setVolume(volume: number): void {
console.log(`Volume set to ${volume}`);
}

turnOff(): void {
console.log('Sound System turned off');
}
}

Now, you have HomeTheaterFacade class acting as facade that provides a simplified interface to interact with the home theater system.

class HomeTheaterFacade {
private dvdPlayer: DVDPlayer;
private projector: Projector;
private screen: Screen;
private soundSystem: SoundSystem;

constructor() {
this.dvdPlayer = new DVDPlayer();
this.projector = new Projector();
this.screen = new Screen();
this.soundSystem = new SoundSystem();
}

watchMovie(): void {
this.screen.down();
this.projector.turnOn();
this.projector.setInput('DVD');
this.dvdPlayer.turnOn();
this.dvdPlayer.playMovie();
this.soundSystem.turnOn();
this.soundSystem.setVolume(10);
}

endMovie(): void {
this.dvdPlayer.turnOff();
this.soundSystem.turnOff();
this.projector.turnOff();
this.screen.up();
}
}

The client code only needs to create an instance of the facade and call the relevant methods, such as watchMovie() and endMovie(). The facade class internally manages the interactions with the individual components of the home theater system. Much easier, right?

// Client Code
const homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie();
// Output:
// Screen lowered
// Projector turned on
// Input set to DVD
// DVD Player turned on
// Movie playing
// Sound System turned on
// Volume set to 10

homeTheater.endMovie();
// Output:
// DVD Player turned off
// Sound System turned off
// Projector turned off
// Screen raised

🧑🏻‍💻 Use it or Avoid it

When to use it:

  • To provide a simple and unified interface to a complex subsystem, making it easier to use and understand.
  • To hide the complexities and dependencies of individual subsystem components from the client code.
  • To decouple the client code from the subsystem, promoting loose coupling and easier maintenance.

When to avoid it:

  • If the underlying subsystem is simple and has only a few components. In such cases, the added abstraction may introduce unnecessary complexity.
  • If you need fine-grained control over individual subsystem components.

--

--

365kim

Web Front-End Developer who believes Every Day Counts!