Design Pattern: Facade Pattern in Python

In a large system, we end up with many submodules or sub-systems, and we do not want to expose all the submodules for different reasons(security, complexity, etc.). In that case, Facade pattern can help us to hide the internal complexity, and expose only the required simplified functions/interfaces.

Facade works as an abstraction layer, over the underlying complex system. The client communicates with the facade, and the facade communicates with the subsystems.

Facade Pattern
Facade Pattern

NOTES

In this article, we discuss the implementation of the Facade Pattern in Python.

See the Facade in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Facade Pattern-

Implementation

Follow the steps below to implement Facade pattern in Python-

Here is a simple example of Facade implementation-

# First subsystem
class Subsystem1:
    def operation1(self):
        print("Subsystem 1: operation 1")

    def operation2(self):
        print("Subsystem 1: operation 2")


# Second subsystem
class Subsystem2:
    def operation3(self):
        print("Subsystem 2: operation 3")

    def operation4(self):
        print("Subsystem 2: operation 4")


# Third subsystem
class Subsystem3:
    def operation5(self):
        print("Subsystem 3: operation 5")


# Facade
class Facade:
    def __init__(self):
        # Initialize subsystems
        self.subsystem1 = Subsystem1()
        self.subsystem2 = Subsystem2()
        self.subsystem3 = Subsystem3()

    def exampleOp1(self):
        # Use operation from subsystem as required
        self.subsystem1.operation1()
        self.subsystem2.operation3()

    def exampleOp2(self):
        # Use operation from subsystem as required
        self.subsystem1.operation2()
        self.subsystem3.operation5()


# Demo usage
if __name__ == "__main__":
    facade = Facade()

    facade.exampleOp1()
    facade.exampleOp2()
Python

Output of the above code will be –

Subsystem 1: operation 1
Subsystem 2: operation 3
Subsystem 1: operation 2
Subsystem 3: operation 5
Plaintext

Examples

Example #1: Travel Plan

Car Class [subsystem class]

import random


# Subsystem: Car
class Car:
    def start_engine(self):
        print("Start Engine")

    def stop_engine(self):
        print("Stop Engine")

    def go_straight(self):
        print("Go Straight: ↑")

    def go_left(self):
        print("Go Left: ←")

    def go_right(self):
        print("Go Right: →")

    def get_distance_travelled(self):
        # Random calculation for demo purposes
        return round(
            (random.randint(0, 180) * ((10000 - 100) * 10 + 1) + 100 * 10) / 10.0, 2
        )
Python

Point Class [subsystem class]

# Subsystem: Point (for coordinates)
class Point:
    def __init__(self, lat: float, lng: float):
        self._lat = lat
        self._lng = lng

    # Getters and Setters for Latitude
    @property
    def lat(self):
        return self._lat

    @lat.setter
    def lat(self, value: float):
        self._lat = value

    @lat.deleter
    def lat(self):
        del self._lat

    # Getters and Setters for Longitude
    @property
    def lng(self):
        return self._lng

    @lng.setter
    def lng(self, value: float):
        self._lng = value

    @lng.deleter
    def lng(self):
        del self._lng
Python

Direction Class [subsystem class]

# Subsystem: Direction
class Direction:
    def __init__(
        self, start_lat: float, start_lng: float, end_lat: float, end_lng: float
    ):
        self._start_lat = start_lat
        self._start_lng = start_lng
        self._end_lat = end_lat
        self._end_lng = end_lng

    def get_location_details(self, lat: float, lng: float):
        print("Country: ABC")
        print("City: DEF")
        print("State: GHI")
        print("Zip: 101010")

    def get_current_location(self):
        # Random calculation for demo purposes
        current_lat = random.uniform(-90, 90)
        current_lng = random.uniform(-180, 180)
        return Point(current_lat, current_lng)

    def get_next_move(self):
        # Randomly choose the next move
        next_moves = ["straight", "left", "right"]
        return random.choice(next_moves)

    def get_full_route(self):
        points = []
        for _ in range(10):
            # Random calculation for demo purposes
            current_lat = random.uniform(-90, 90)
            current_lng = random.uniform(-180, 180)
            points.append(Point(current_lat, current_lng))
        return points
Python

Toll Class [subsystem class]

# Subsystem: Toll
class Toll:
    def get_toll_points(self, lat: float, lng: float):
        points = []
        for _ in range(10):
            current_lat = random.uniform(-90, 90)
            current_lng = random.uniform(-180, 180)
            points.append(Point(current_lat, current_lng))
        return points

    def get_toll_amount(self, toll_point_id: float):
        return random.uniform(0, 100)

    def get_total_toll(self, lat: float, lng: float):
        return random.uniform(0, 100)
Python

Weather Class [subsystem class]

# Subsystem: Weather
class Weather:
    def get_weather_info(self, lat: float, lng: float):
        print("Temperature: 20.7°C")
        print("Precipitation: 1%")
        print("Humidity: 73%")
        print("Wind: 8 km/h")
Python

Facade Class

# Facade: TravelFacade
class TravelFacade:
    def __init__(
        self, start_lat: float, start_lng: float, end_lat: float, end_lng: float
    ):
        self._start_lat = start_lat
        self._start_lng = start_lng
        self._end_lat = end_lat
        self._end_lng = end_lng
        self._direction = Direction(start_lat, start_lng, end_lat, end_lng)
        self._car = Car()
        self._toll = Toll()
        self._weather = Weather()

    def get_route(self):
        return self._direction.get_full_route()

    def get_location_info(self, lat: float, lng: float):
        self._direction.get_location_details(lat, lng)
        self._weather.get_weather_info(lat, lng)

    def get_current_location(self):
        return self._direction.get_current_location()

    def operate_car(self):
        full_route = self._direction.get_full_route()
        self._car.start_engine()
        for point in full_route:
            next_move = self._direction.get_next_move()
            if next_move == "straight":
                self._car.go_straight()
            elif next_move == "left":
                self._car.go_left()
            elif next_move == "right":
                self._car.go_right()
        self._car.stop_engine()

    def get_total_toll_amount(self, lat: float, lng: float):
        print(f"Total Toll Amount: {self._toll.get_total_toll(lat, lng):.2f}")
Python

Demo

# Demo: Using the Facade
if __name__ == "__main__":
    travel_facade = TravelFacade(10, 10, 20, 30)
    current_location = travel_facade.get_current_location()
    print(f"Current Latitude: {current_location.lat}")
    print(f"Current Longitude: {current_location.lng}")

    travel_facade.get_location_info(20, 30)
    travel_facade.get_total_toll_amount(20, 30)
    travel_facade.operate_car()
Python

Output

Output of the above demo code will be as below. Output may differ for you as most of the methods here use dummy(with random) code.

Current Latitude: 3.942649018722733
Current Longitude: 75.2548665877676

Country: ABC
City: DEF
State: GHI
Zip: 101010
Temperature: 20.7°C
Precipitation: 1%
Humidity: 73%
Wind: 8 km/h

Total Toll Amount: 91.00

Start Engine
Go Right: →
Go Left: ←
Go Straight: ↑
Go Left: ←
Go Straight: ↑
Go Straight: ↑
Go Left: ←
Go Straight: ↑
Go Straight: ↑
Go Straight: ↑
Stop Engine
Plaintext

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Facade pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.