Skip to main content

Real World Implementation Facade Pattern

Let's take an example of a Home Theater system. This system might have multiple components, like Amplifier, DvdPlayer, Projector, and Lights. Each of these components can have its own set of complex operations, but when you want to watch a movie, you would like to simply press one button, and all the necessary operations are done.

Real World Implementation

First, let's define our subsystems (Amplifier, DvdPlayer, Projector, and Lights):

class Amplifier {
turnOn() {
console.log("Amplifier is turned on");
}

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

class DvdPlayer {
turnOn() {
console.log("DvdPlayer is turned on");
}

play(movie: string) {
console.log(`Playing ${movie}`);
}
}

class Projector {
turnOn() {
console.log("Projector is turned on");
}

setInput(dvdPlayer: DvdPlayer) {
console.log("Projector input set to DvdPlayer");
}
}

class Lights {
dim(level: number) {
console.log(`Lights are dimmed to ${level}%`);
}
}

Now, we create a HomeTheaterFacade to simplify the operation of watching a movie:

class HomeTheaterFacade {
private amplifier: Amplifier;
private dvdPlayer: DvdPlayer;
private projector: Projector;
private lights: Lights;

constructor(
amplifier: Amplifier,
dvdPlayer: DvdPlayer,
projector: Projector,
lights: Lights
) {
this.amplifier = amplifier;
this.dvdPlayer = dvdPlayer;
this.projector = projector;
this.lights = lights;
}

watchMovie(movie: string) {
console.log("Get ready to watch a movie...");
this.lights.dim(10);
this.amplifier.turnOn();
this.amplifier.setVolume(5);
this.dvdPlayer.turnOn();
this.projector.setInput(this.dvdPlayer);
this.dvdPlayer.play(movie);
}
}

The watchMovie method in the HomeTheaterFacade class is an example of a facade operation. It's a simple interface to a set of more complex subsystems and operations, which makes it easier for clients to use.

Here is how a client would use the HomeTheaterFacade:

let amplifier = new Amplifier();
let dvdPlayer = new DvdPlayer();
let projector = new Projector();
let lights = new Lights();

let homeTheater = new HomeTheaterFacade(
amplifier,
dvdPlayer,
projector,
lights
);

homeTheater.watchMovie("Inception");

In this example, the HomeTheaterFacade class hides the complexities of the subsystem and provides a simplified interface to the client. The client does not need to worry about how to operate the Amplifier, DvdPlayer, Projector, and Lights individually to watch a movie. They just need to call the watchMovie method on the HomeTheaterFacade.

Advantages Of The Facade Pattern

The Facade pattern offers several advantages, especially when dealing with complex systems. Here are some advantages offered by the Facade pattern.

Simplified Interface

The Facade pattern provides a simplified interface to a complex subsystem. In our Home Theater example, instead of manually managing each component of the theater system (turning on the amplifier, setting the volume, turning on the DVD player, setting the input for the projector, and dimming the lights), the client can simply call the watchMovie() method:

homeTheater.watchMovie("Inception");

Reduced Dependencies

The Facade pattern reduces the dependencies from the client code to the subsystem classes. The client doesn't need to know about Amplifier, DvdPlayer, Projector, and Lights classes or their methods. They interact only with the HomeTheaterFacade class, which significantly reduces coupling.

let homeTheater = new HomeTheaterFacade(
amplifier,
dvdPlayer,
projector,
lights
);

Decoupling of Subsystems and Client

The Facade pattern decouples the client and the subsystems. Changes in the subsystem classes have minimal effect on the client code as long as the facade's interface stays the same. For instance, if we add more methods or change the implementation within the Amplifier class, it won't affect the client code:

class Amplifier {
turnOn() {
/* ... */
}
setVolume(level: number) {
/* ... */
}
// More methods or changes here won't affect the client code as long as they're not used in the facade.
}

Easier to Use

By hiding the complexities and providing a simple interface, the subsystem becomes easier to use. A client doesn't need to understand how the subsystem works in order to use it.

homeTheater.watchMovie("Inception"); // Easier to use than dealing with each component individually.

Promotes Layering

The Facade pattern promotes a layered architecture in your code. You can use facades to define entry points to each layer of your architecture, which helps to structure and organize the code.

class HomeTheaterFacade {
/* Facade for the Home Theater system layer */
}
// More Facades could be added for other layers in a larger system.

These are just a few advantages of using the Facade design pattern. It's worth noting that while Facade can simplify a lot of things, it's important not to overuse it. Adding a facade when the subsystem is not complex might add unnecessary abstraction to your code. Like any design pattern, it should be used judiciously.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.

SEE COURSE DETAILS

What Can You Do Next 🙏😊

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.

YouTube @cloudaffle