Understanding Facade Design Pattern

Understanding Facade Design Pattern

18 Sep 2024
Intermediate
153K Views
37 min read
Learn with an interactive course and practical hands-on labs

⭐ .NET Design Patterns Course: Design Patterns in C# Online Training

Facade Design Pattern

Facade Design Pattern is an important concept in software design. It gives a simplified interface to a complicated system of classes, libraries, or frameworks, letting users interact with a single point rather than several intricate subsystems. This pattern keeps the system ordered, lowers complexity, and facilitates management and maintenance.

In this design pattern tutorial, we will look at the Facade Design Pattern and answer the question, "What is the Facade Design Pattern?". Furthermore, "When should I use the Facade Design Pattern?" We'll also examine examples of the Facade Design Pattern in use. So, let's start by addressing the question, "What is the Facade Design Pattern?"

What is a facade Pattern?

  • The Facade Design Pattern is a structural design pattern that simplifies interactions between a complex system of classes by providing a unified interface through a facade object.
  • Instead of interacting directly with multiple subsystems, clients communicate with the facade, which handles and organizes the underlying processes.
  • This reduces the complexity of interactions and promotes easier management and loose coupling between the client and the subsystems.

Real-world Illustration of Facade Design Pattern

Real-world Illustration of Facade Design Pattern

  • When you use a TV remote, you don't need to operate the internal electronics directly.
  • Instead, you just press buttons to change the channel or adjust the volume.
  • It’s the remote that simplifies everything by hiding the complexity of the TV's inner workings.
  • Without the remote, you would have to manually operate the TV’s controls, which would be more difficult.
  • The remote acts as a facade, making it easy for you to control the TV without dealing with the complex systems inside.

Facade Design Pattern Basic Structure and Implementation

The structure for the implementation of the Facade Design Pattern is given below:

Facade Design Pattern Basic Structure and Implementation

The classes, interfaces, and objects in the above structure are as follows:

  • Facade: An interface that provides simplified operations for the user by interacting with complex subsystems behind the scenes.
  • ConcreteFacade: A class that implements the Facade interface, coordinating and managing the interactions between subsystems.
  • Subsystem: Classes representing complex functionalities or operations, such as specific components of a larger system.
  • ConcreteSubsystemA/B: Classes that perform complex operations and are accessed through the Facade rather than directly by the client.
Real Life Example:

Real Life Example:

Subsystems (Home Appliances)

  • In a home, it is common to have various appliances like the air conditioner, heater, and lights.
  • Each appliance has its own complex controls and settings.

Facade (Home Automation System)

  • It is the Home Automation System that acts as a facade.
  • Instead of manually adjusting each appliance, you use a single control panel.

Operation Flow

  • Simplified Interaction: When you want to set the temperature or turn on the lights, you make these adjustments through the home automation control panel.
  • Command Handling: The control panel (facade) sends commands to the appliances. For example, if you set the temperature, it is the control panel that instructs both the heater and the air conditioner.
  • Subsystem Response: Each appliance (air conditioner, heater, lights) then responds to these commands. It is the appliances that adjust their settings based on the instructions from the control panel.

How the Facade Helps

  • Unified Interface: It is the Home Automation System that provides a single point of control. This means you don’t need to manage each appliance’s complex settings separately.
  • Reduced Complexity: By using the facade, it is not necessary to deal with each appliance individually. It simplifies your experience by handling all interactions through one interface.
  • Improved Usability: The facade makes it easier to control multiple appliances. It is the control panel that manages everything, making your home environment more convenient and efficient.
Let's explore this conceptin different languages, such asC# Compiler, Java Compiler, Python Compiler, and TypeScript Compiler.

Example


using System;

public class AirConditioner
{
    public void TurnOn() => Console.WriteLine("Air Conditioner is now ON.");
    public void TurnOff() => Console.WriteLine("Air Conditioner is now OFF.");
    public void SetTemperature(int temperature) => Console.WriteLine($"Air Conditioner temperature set to {temperature}°C.");
}

public class Heater
{
    public void TurnOn() => Console.WriteLine("Heater is now ON.");
    public void TurnOff() => Console.WriteLine("Heater is now OFF.");
    public void SetTemperature(int temperature) => Console.WriteLine($"Heater temperature set to {temperature}°C.");
}

public class Lights
{
    public void TurnOn() => Console.WriteLine("Lights are now ON.");
    public void TurnOff() => Console.WriteLine("Lights are now OFF.");
}

public class HomeAutomationFacade
{
    private AirConditioner _airConditioner;
    private Heater _heater;
    private Lights _lights;

    public HomeAutomationFacade()
    {
        _airConditioner = new AirConditioner();
        _heater = new Heater();
        _lights = new Lights();
    }

    public void SetTemperature(int temperature)
    {
        Console.WriteLine("Setting temperature...");
        _airConditioner.SetTemperature(temperature);
        _heater.SetTemperature(temperature);
    }

    public void TurnOnHome()
    {
        Console.WriteLine("Turning on the home system...");
        _airConditioner.TurnOn();
        _heater.TurnOn();
        _lights.TurnOn();
    }

    public void TurnOffHome()
    {
        Console.WriteLine("Turning off the home system...");
        _airConditioner.TurnOff();
        _heater.TurnOff();
        _lights.TurnOff();
    }
}

class Program
{
    static void Main(string[] args)
    {
        HomeAutomationFacade homeFacade = new HomeAutomationFacade();
        homeFacade.TurnOnHome();
        homeFacade.SetTemperature(22);
        homeFacade.TurnOffHome();
    }
}
            

public class AirConditioner {
    public void turnOn() { System.out.println("Air Conditioner is now ON."); }
    public void turnOff() { System.out.println("Air Conditioner is now OFF."); }
    public void setTemperature(int temperature) { System.out.println("Air Conditioner temperature set to " + temperature + "°C."); }
}

public class Heater {
    public void turnOn() { System.out.println("Heater is now ON."); }
    public void turnOff() { System.out.println("Heater is now OFF."); }
    public void setTemperature(int temperature) { System.out.println("Heater temperature set to " + temperature + "°C."); }
}

public class Lights {
    public void turnOn() { System.out.println("Lights are now ON."); }
    public void turnOff() { System.out.println("Lights are now OFF."); }
}

public class HomeAutomationFacade {
    private AirConditioner airConditioner;
    private Heater heater;
    private Lights lights;

    public HomeAutomationFacade() {
        airConditioner = new AirConditioner();
        heater = new Heater();
        lights = new Lights();
    }

    public void setTemperature(int temperature) {
        System.out.println("Setting temperature...");
        airConditioner.setTemperature(temperature);
        heater.setTemperature(temperature);
    }

    public void turnOnHome() {
        System.out.println("Turning on the home system...");
        airConditioner.turnOn();
        heater.turnOn();
        lights.turnOn();
    }

    public void turnOffHome() {
        System.out.println("Turning off the home system...");
        airConditioner.turnOff();
        heater.turnOff();
        lights.turnOff();
    }
}

public class Main {
    public static void main(String[] args) {
        HomeAutomationFacade homeFacade = new HomeAutomationFacade();
        homeFacade.turnOnHome();
        homeFacade.setTemperature(22);
        homeFacade.turnOffHome();
    }
}
            

class AirConditioner:
    def turn_on(self):
        print("Air Conditioner is now ON.")
    
    def turn_off(self):
        print("Air Conditioner is now OFF.")
    
    def set_temperature(self, temperature):
        print(f"Air Conditioner temperature set to {temperature}°C.")


class Heater:
    def turn_on(self):
        print("Heater is now ON.")
    
    def turn_off(self):
        print("Heater is now OFF.")
    
    def set_temperature(self, temperature):
        print(f"Heater temperature set to {temperature}°C.")


class Lights:
    def turn_on(self):
        print("Lights are now ON.")
    
    def turn_off(self):
        print("Lights are now OFF.")


class HomeAutomationFacade:
    def __init__(self):
        self.air_conditioner = AirConditioner()
        self.heater = Heater()
        self.lights = Lights()
    
    def set_temperature(self, temperature):
        print("Setting temperature...")
        self.air_conditioner.set_temperature(temperature)
        self.heater.set_temperature(temperature)
    
    def turn_on_home(self):
        print("Turning on the home system...")
        self.air_conditioner.turn_on()
        self.heater.turn_on()
        self.lights.turn_on()
    
    def turn_off_home(self):
        print("Turning off the home system...")
        self.air_conditioner.turn_off()
        self.heater.turn_off()
        self.lights.turn_off()


if __name__ == "__main__":
    home_facade = HomeAutomationFacade()
    home_facade.turn_on_home()
    home_facade.set_temperature(22)
    home_facade.turn_off_home()
            

class AirConditioner {
    turnOn() { console.log("Air Conditioner is now ON."); }
    turnOff() { console.log("Air Conditioner is now OFF."); }
    setTemperature(temperature: number) { console.log(`Air Conditioner temperature set to ${temperature}°C.`); }
}

class Heater {
    turnOn() { console.log("Heater is now ON."); }
    turnOff() { console.log("Heater is now OFF."); }
    setTemperature(temperature: number) { console.log(`Heater temperature set to ${temperature}°C.`); }
}

class Lights {
    turnOn() { console.log("Lights are now ON."); }
    turnOff() { console.log("Lights are now OFF."); }
}

class HomeAutomationFacade {
    private airConditioner: AirConditioner;
    private heater: Heater;
    private lights: Lights;

    constructor() {
        this.airConditioner = new AirConditioner();
        this.heater = new Heater();
        this.lights = new Lights();
    }

    setTemperature(temperature: number) {
        console.log("Setting temperature...");
        this.airConditioner.setTemperature(temperature);
        this.heater.setTemperature(temperature);
    }

    turnOnHome() {
        console.log("Turning on the home system...");
        this.airConditioner.turnOn();
        this.heater.turnOn();
        this.lights.turnOn();
    }

    turnOffHome() {
        console.log("Turning off the home system...");
        this.airConditioner.turnOff();
        this.heater.turnOff();
        this.lights.turnOff();
    }
}

// Client code
const homeFacade = new HomeAutomationFacade();
homeFacade.turnOnHome();
homeFacade.setTemperature(22);
homeFacade.turnOffHome();
            

class AirConditioner {
    turnOn() { console.log("Air Conditioner is now ON."); }
    turnOff() { console.log("Air Conditioner is now OFF."); }
    setTemperature(temperature) { console.log(`Air Conditioner temperature set to ${temperature}°C.`); }
}

class Heater {
    turnOn() { console.log("Heater is now ON."); }
    turnOff() { console.log("Heater is now OFF."); }
    setTemperature(temperature) { console.log(`Heater temperature set to ${temperature}°C.`); }
}

class Lights {
    turnOn() { console.log("Lights are now ON."); }
    turnOff() { console.log("Lights are now OFF."); }
}

class HomeAutomationFacade {
    constructor() {
        this.airConditioner = new AirConditioner();
        this.heater = new Heater();
        this.lights = new Lights();
    }

    setTemperature(temperature) {
        console.log("Setting temperature...");
        this.airConditioner.setTemperature(temperature);
        this.heater.setTemperature(temperature);
    }

    turnOnHome() {
        console.log("Turning on the home system...");
        this.airConditioner.turnOn();
        this.heater.turnOn();
        this.lights.turnOn();
    }

    turnOffHome() {
        console.log("Turning off the home system...");
        this.airConditioner.turnOff();
        this.heater.turnOff();
        this.lights.turnOff();
    }
}

// Client code
const homeFacade = new HomeAutomationFacade();
homeFacade.turnOnHome();
homeFacade.setTemperature(22);
homeFacade.turnOffHome();
            

Output


Turning on the home system...
Air Conditioner is now ON.
Heater is now ON.
Lights are now ON.
Setting temperature...
Air Conditioner temperature set to 22°C.
Heater temperature set to 22°C.
Turning off the home system...
Air Conditioner is now OFF.
Heater is now OFF.
Lights are now OFF.

Explanation

  • This code demonstrates the Facade Design Pattern through a home automation system.
  • It is the HomeAutomationFacade that simplifies the control of multiple subsystems like AirConditioner, Heater, and Lights.
  • Instead of interacting with each appliance separately, it is possible to manage everything with a single interface.
  • This makes it easier to control home appliances through a few simple commands.

Applications of Facade Design Pattern

Use the Facade pattern when you require a simple interface to a complex subsystem.

  • Subsystems frequently evolve into more sophisticated structures throughout time.
  • Even applying design patterns often results in the creation of new classes.
  • A subsystem may become more adaptable and easier to reuse in multiple situations, but the amount of configuration and boilerplate code required from a client increases.
  • The Facade seeks to address this issue by offering a shortcut to the subsystem's most often-used features, which meet the majority of client requirements.

Use the Facade to divide a subsystem into layers.

  • Create facades to define the entry points for each level of a subsystem.
  • To eliminate connectivity between several subsystems, they must be required to communicate exclusively through facades.
  • Let's get back to our video conversion framework.
  • It can be divided into two layers: video and audio-related.
  • You can create a facade for each layer and then use those facades to connect with the classes in that layer. This method is quite similar to the Mediator pattern.

Benefits of Facade Design Pattern

  • It simplifies the interaction with complex subsystems.
  • It provides a unified interface for easier control.
  • It hides the complexity of multiple subsystems from the client.
  • Because subsystems are accessed through the facade, it is easier to manage and maintain them.
  • The client code becomes cleaner and more straightforward since it does not require detailed knowledge of subsystem operations.

When to use the Facade Method Design Pattern

  • A Facade provides a simple default view of the subsystem that is suitable for the majority of clients.
  • Only consumers who require greater customization will need to look beyond the facade.
  • Clients and an abstraction's implementation classes are highly interdependent.
  • A facade that isolates the subsystem from customers and other subsystems, encouraging subsystem independence and portability.
  • Facades define an entry point into each subsystem level.
  • If subsystems are dependent, you can reduce their dependencies by limiting their communication to their facades.

When not to use the Facade Method Design Pattern

  • It is unnecessary to use the Facade pattern when the system lacks multiple complex subsystems, as it can add unneeded abstraction.
  • In small-scale applications, where direct access to components is efficient, a facade might create unnecessary overhead.
  • It can also violate the Single Responsibility Principle by grouping different operations in one interface.
  • If using a facade complicates rather than simplifies the system, it is likely over-engineering and should be avoided for straightforward use cases.

Relationship with Other Patterns

Mediator Pattern: The Facade pattern is similar to the Mediator pattern in that it simplifies interactions, but it is focused on providing a unified interface to complex subsystems.
Adapter Pattern: It is different from the Adapter pattern because it alters interfaces to make them compatible, while the Facade simplifies them without changing the underlying functionality.
Abstract Factory Pattern: The Facade pattern can work with the Abstract Factory pattern to create and manage complex subsystems while hiding their complexities.
Singleton Pattern: It is often used with the Singleton pattern to ensure only one instance of the facade exists, maintaining control over the system.
Summary
The Facade Design Pattern provides a simplified interface to complex systems by allowing users to interact with a single point rather than multiple subsystems. It helps reduce complexity, improves manageability, and makes the system easier to maintain. The facade acts as a gateway to handle underlying operations while keeping the client code clean and straightforward. For more information, see Scholarhat's Software Architecture and Design Certification Training.

FAQs

The Facade Design Pattern's principal objective is to provide a simpler interface to a complex system, allowing clients to interact with it from a single location. This decreases complexity, makes the system more manageable, and encourages loose connectivity between the client and subsystems.

The Mediator Design Pattern is an alternative to the Facade Design Pattern, as it focuses on managing communication between several objects, allowing for more flexible interactions. Another alternative is the Adapter Design Pattern, which alters interfaces to allow incompatible systems to function together.

The Facade Pattern alleviates the challenge of maintaining complex subsystems by offering a single, unified interface. It lowers client complexity, enhances system organization, and makes code more maintainable and extensible.
Share Article
About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

Shailendra Chauhan, Founder and CEO of ScholarHat by DotNetTricks, is a renowned expert in System Design, Software Architecture, Azure Cloud, .NET, Angular, React, Node.js, Microservices, DevOps, and Cross-Platform Mobile App Development. His skill set extends into emerging fields like Data Science, Python, Azure AI/ML, and Generative AI, making him a well-rounded expert who bridges traditional development frameworks with cutting-edge advancements. Recognized as a Microsoft Most Valuable Professional (MVP) for an impressive 9 consecutive years (2016–2024), he has consistently demonstrated excellence in delivering impactful solutions and inspiring learners.

Shailendra’s unique, hands-on training programs and bestselling books have empowered thousands of professionals to excel in their careers and crack tough interviews. A visionary leader, he continues to revolutionize technology education with his innovative approach.
Accept cookies & close this