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.
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 DETAILSWhat 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.