Definition

The Façade design pattern defines a unified, higher-level interface to wrap a complicated set of interfaces in a subsystem. It protects client code from sophisticated functionality in one or more subsystems by providing an interface or API to work with that is better and significantly easier to use.

Façades are usually combined with some other design patterns, and often are implemented as Singleton factories. It falls under the structural desing pattern category.

Use Cases

The most common use cases for this design pattern would be:

  • When we want to simplify the interface to access several external/internal APIs in multiple subsystems.
  • When we are dealing with on progress API that we want to provide a consistent API to the client code.
  • Hiding legacy code that the client system should not be concerned about, and exposes only necessary parts in a clean interface.

Examples

Some of the examples of that pattern in the real world are the .animate() and .css() methods of jQuery as Addy Osmani pointed out in his book essential design patterns.

When we used them, we're actually using a Façade - the simpler public interface that avoids us having to manually call the many internal methods in jQuery core required to get some behavior working. This also avoids the need to manually interact with DOM APIs and maintain state variables.

A user example of the Façade pattern could be an app that is providing options to book a train, flight or hotel.

function TravelFacade(reservationType) {
    this.reservationType = reservationType;

    this.flight = new FlightBooker();
    this.hotel = new HotelBooker();
    this.train = new TrainBooker();
}

TravelFacade.prototype.book = function (reservationInfo) {
    switch (this.reservationType) {
        case 'Flight':
            // book flight;
            this.flight.book(reservationInfo);
            break;
        case 'Hotel':
            // book hotel;
            this.hotel.book(reservationInfo);
            break;
        case 'Train':
            // book Train;
            this.train.book(reservationInfo);
            break;
        case 'Flight_And_Hotel':
            // book Flight and Hotel
            this.flight.book(reservationInfo);
            this.hotel.book(reservationInfo);
            break;
        case 'Train_And_Hotel':
            // book Train and Hotel
            this.train.book(reservationInfo);
            this.hotel.book(reservationInfo);
            break;
        default:
            // throw an error
            throw Error('Reservation type is not supported.');
    }
}

function FlightBooker() {
    function book(bookingInfo) {
        // handle booking flight
        console.log(bookingInfo.flight);
    }

    // revealing module pattern
    return {
        book: book
    }
}

function TrainBooker() {
    function book(bookingInfo) {
        // handle train booking
        console.log(bookingInfo.train);
    }

    // revealing module pattern
    return {
        book: book
    }
}

function HotelBooker() {
    function book(bookingInfo) {
        // handle hotel booking
        console.log(bookingInfo.hotel);
    }

    // revealing module pattern
    return {
        book: book
    }
}

let flight = {
    'departure_datetime': '21/09/2017 09:00',
    'return_datetime': '25/09/2017 22:00',
    'from': 'New York',
    'to': 'London'
};

let train = {
    'departure_datetime': '22/09/2017 20:00',
    'return_datetime': '25/09/2017 10:00',
    'from': 'London',
    'to': 'Edinburgh'
};

let hotel = {
    'check_in_date': '22/09/2017',
    'nights': 1,
    'city': 'London',
    'hotel_name': 'Four Seasons Hotel'
};

let travel1 = new TravelFacade('Flight_And_Hotel');
travel1.book({flight, hotel});
// {departure_datetime: "21/09/2017 09:00", return_datetime: "25/09/2017 22:00", from: "New York", to: "London"}
// {check_in_date: "22/09/2017", nights: 1, city: "London", hotel_name: "Four Seasons Hotel"}

hotel = {
    'check_in_date': '22/09/2017 20:00',
    'nights': 3,
    'city': 'Edinbrugh',
    'hotel_name': 'The Balmoral'
};

let travel2 = new TravelFacade('Train_And_Hotel');
travel2.book({train, hotel});
// {departure_datetime: "22/09/2017 20:00", return_datetime: "25/09/2017 10:00", from: "London", to: "Edinburgh"}
// {check_in_date: "22/09/2017 20:00", nights: 3, city: "Edinbrugh", hotel_name: "The Balmoral"}

FlightBooker, TrainBooker and HotelBooker are different sub-systems of large system: TravelFacade. TravelFacade offers a simple interface to book one of the following options: Flight Booking, Train Booking, Hotel Booking, Flight + Hotel booking, and Train + Hotel booking. book API from TravelFacade internally calls APIs of sub-systems: FlightBooker.book(bookingInfo), TrainBooker.book(bookingInfo) and HotelBooker.book(bookingInfo). In this way, TravelFacade provides simpler and easier API with-out exposing sub-system APIs.