Facade

Facades are used as a simple, high-level interface to a complex subsystem, used to hide that complexity from the client. This is seen as a way to simplify access to libraries, frameworks, or other complex sets of classes.

TL;DR

Facade patterns provide a simple interface to a complex subsystem.

Problem

Suppose you need to make your code work with a broad set of objects that are part of a sophisticated library, wherein you have to initialize many objects, track dependencies, and execute methods in the correct order.

To integrate this, your own code might then become tightly coupled with the external library, making it very difficult to maintain, especially if you only need a small subset of the library’s functionality.

Solution

The Facade pattern shines when there are many subsystems that need to be executed, but the client code only cares about coarse-grained access to them, possibly without too much detail. For example, we might have home automation systems controlled by a simple application that acts based on whether the user arrives home, leaves, or is hosting a movie night.

Rather than have the client know about each individual step for light, HVAC, music, and security systems, we can implement a Facade that manages all the required steps:

# Complex subsystem classes
class SecuritySystem:
    def arm(self):
        print("Security system armed")
    
    def disarm(self):
        print("Security system disarmed")
 
class LightingSystem:
    def turn_on_all(self):
        print("All lights turned on")
    
    def turn_off_all(self):
        print("All lights turned off")
    
    def set_mood_lighting(self):
        print("Mood lighting activated")
 
class HvacSystem:
    def set_temperature(self, temp):
        print(f"Temperature set to {temp}°F")
    
    def turn_on_ac(self):
        print("Air conditioning turned on")
    
    def turn_off_ac(self):
        print("Air conditioning turned off")
 
class MusicSystem:
    def play_playlist(self, playlist):
        print(f"Playing playlist: {playlist}")
    
    def stop(self):
        print("Music stopped")
 
# Facade class that provides a simple interface
class SmartHomeFacade:
    def __init__(self):
        self.security = SecuritySystem()
        self.lights = LightingSystem()
        self.hvac = HvacSystem()
        self.music = MusicSystem()
    
    def leave_home(self):
        """Simple method to execute multiple operations when leaving home"""
        print("Leaving home...")
        self.lights.turn_off_all()
        self.hvac.turn_off_ac()
        self.music.stop()
        self.security.arm()
        print("Home secured for departure\n")
    
    def arrive_home(self):
        """Simple method to execute multiple operations when arriving home"""
        print("Arriving home...")
        self.security.disarm()
        self.lights.turn_on_all()
        self.hvac.set_temperature(72)
        self.music.play_playlist("Welcome Home")
        print("Home ready for arrival\n")
    
    def movie_night(self):
        """Simple method to set up movie night ambiance"""
        print("Setting up movie night...")
        self.lights.set_mood_lighting()
        self.hvac.set_temperature(68)
        self.music.stop()
        print("Movie night setup complete\n")
 
# Usage example
if __name__ == "__main__":
    # Without facade, client would need to interact with all subsystems
    # security = SecuritySystem()
    # lights = LightingSystem()
    # hvac = HvacSystem()
    # music = MusicSystem()
    # 
    # # Complex operations requiring multiple steps
    # lights.turn_off_all()
    # hvac.turn_off_ac()
    # music.stop()
    # security.arm()
    
    # With facade, client has a simple interface
    smart_home = SmartHomeFacade()
    
    # Simple method calls handle complex operations
    smart_home.leave_home()
    smart_home.arrive_home()
    smart_home.movie_night()