Skip to main content

Facade Design Pattern

Problem​

You: Hi Shubh, today I want to learn about the Facade Design Pattern. I thought, why not learn from you? If you don't mind, can you please explain it to me?

Shubh: Definitely! Let's try to understand the problems without the Facade Design Pattern.

You: Yeah! That sounds good.

Shubh: Let's say we have to create a functionality related to a home theatre system. The functionalities would include lowering the projector, playing the DVD, and adjusting the volume. How would you implement this?

You: I would create classes like Projector for managing the projector, DVDPlayer for playing and stopping the DVD, and VolumeController for controlling the volume.

Shubh: Good start! Then how would you combine them to watch a specific movie?

You: To play the movie, I would call the methods we created, like lowerWhiteBoard(), insertDVD(), and setVolume(x). For stopping the movie, I would call the reverse methods.

Shubh: Let's say you wrote that code (to play a movie) in XYZ.java. Now, in the future, if you need to do the same thing in ABC.java, what would you do?

You: I would call the same methods again, like lowerWhiteBoard(), insertDVD(), and setVolume(x).

Shubh: Now imagine if we had only three functions, but what if there were a hundred functions required to perform a task (like playing a movie)? We would have to call these functions repeatedly in different files. This also means if some APIs start behaving weirdly, we need to change them in every file they are called.

You: You're right! I didn't think about that.

Shubh: Why don't we create a Facade (an interface) like startMovie()? This Facade will internally call all the required methods like lowerWhiteBoard(), insertDVD(), and setVolume(x). If we need to make any changes in the future, we'll update them in the Facade, not in hundreds of files.

UML​

Facade Design Pattern

UML for Facade Design Pattern

Shubh: So, whenever we have a complex system with potentially hundreds of components that may or may not interact among themselves, it's better to use the Facade Design Pattern. Instead of letting the client directly interact with the complex system, we let the Facade manage the interactions, and the client uses the Facade.

Code Implementation​

Projector Class​

Projector.java
public class Projector {
private boolean isWhiteBoardDown;

public void turnOn() {
System.out.println("Projector is turned ON");
}

public void turnOff() {
System.out.println("Projector is turned OFF");
}

public void lowerWhiteBoard() {
if (!isWhiteBoardDown) {
isWhiteBoardDown = true;
System.out.println("WhiteBoard is lowered");
}
}

public void raiseWhiteBoard() {
if (isWhiteBoardDown) {
isWhiteBoardDown = false;
System.out.println("WhiteBoard is raised");
}
}
}

DVDPlayer Class​

DVDPlayer.java
public class DVDplayer {
public void insertDVD() {
System.out.println("DVD inserted");
}

public void ejectDVD() {
System.out.println("DVD ejected");
}
}

VolumeController Class​

VolumeController.java
public class VolumeController {
public void setVolume(int level) {
System.out.println("Volume level set to: " + level);
}
}

HomeTheatreFacade Class​

HomeTheatreFacade.java
public class HomeTheatreFacade {
Projector projector;
DVDplayer dvdPlayer;
VolumeController volumeController;

HomeTheatreFacade(Projector projector, DVDplayer dvdPlayer, VolumeController volumeController) {
this.projector = projector;
this.dvdPlayer = dvdPlayer;
this.volumeController = volumeController;
}

void watchMovie(String name) {
System.out.println("Get ready to watch the movie!");

projector.lowerWhiteBoard();
projector.turnOn();
dvdPlayer.insertDVD();
volumeController.setVolume(70);

System.out.println("Playing movie: " + name);
}

void endMovie() {
projector.raiseWhiteBoard();
projector.turnOff();
dvdPlayer.ejectDVD();

System.out.println("Movie ended");
}
}

Main Class (Client Code)​

Main.java
public class Main {
public static void main(String[] args) throws InterruptedException {
Projector projector = new Projector();
DVDplayer dvdPlayer = new DVDplayer();
VolumeController volumeController = new VolumeController();

HomeTheatreFacade homeTheatre = new HomeTheatreFacade(projector, dvdPlayer, volumeController);

Thread.sleep(3000);
System.out.println("---------------------------------");
homeTheatre.watchMovie("Mahabharat");
System.out.println("---------------------------------");

Thread.sleep(3000);
System.out.println("---------------------------------");
homeTheatre.endMovie();
System.out.println("---------------------------------");
}
}

Key Benefits of the Facade Design Pattern​

Before watching, make sure you give it a try
  • Simplified Interface: The Facade provides a simple and unified interface to the complex subsystem. This reduces the need for clients to deal with multiple components and their complexities directly.

  • Improved Code Maintenance: By centralizing complex interactions within a single Facade, changes to the subsystem are isolated, making the code easier to maintain and update.

  • Loose Coupling: The Facade decouples the client from the complex subsystem. This makes the system more modular and easier to extend or modify without affecting the client.

  • Easier to Use: The Facade hides the complexity of the subsystem components, providing a more straightforward and user-friendly API.

  • Scalability: In large systems, using a Facade allows you to scale functionality without overwhelming the client code with too many dependencies and interactions.