Design Pattern: Facade Pattern in TypeScript

Facade adds a new layer around a bunch of subsystems, and wraps those. Clients interact with the Facade, and are not aware of the systems.

NOTES

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

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 for the Facade pattern implementation in TypeScript-

  • Create a facade class.
  • Define private properties of the type of subsystem classes.
  • In the constructor initialize the subsystem class.
  • Define methods in the facade, and in those methods call methods from the subsystem classes.
  • The facade can be initialized and used normally.

Here is a simple Facade implementation-

// Facade pattern implementation in TypeScript

// First subsystem
class Subsystem1 {
    operation1(): void {
        console.log("Subsystem 1: operation 1");
    }

    operation2(): void {
        console.log("Subsystem 1: operation 2");
    }
}

// Second subsystem
class Subsystem2 {
    operation3(): void {
        console.log("Subsystem 2: operation 3");
    }

    operation4(): void {
        console.log("Subsystem 2: operation 3");
    }
}

// Third subsystem
class Subsystem3 {
    operation5(): void {
        console.log("Subsystem 3: operation 5");
    }
}

// Facade
class Facade {
    private subsystem1: Subsystem1;
    private subsystem2: Subsystem2;
    private subsystem3: Subsystem3;

    constructor() {
        // Initialize subsystems
        this.subsystem1 = new Subsystem1();
        this.subsystem2 = new Subsystem2();
        this.subsystem3 = new Subsystem3();
    }

    exampleOp1(): void {
        // Use operation from subsystem as required
        this.subsystem1.operation1();
        this.subsystem2.operation3();
    }

    exampleOp2(): void {
        // Use operation from subsystem as required
        this.subsystem1.operation2();
        this.subsystem3.operation5();
    }
}

// Demo
const facade = new Facade();

facade.exampleOp1();
facade.exampleOp2();

Output of the above code will be –

Subsystem 1: operation 1
Subsystem 2: operation 3

Subsystem 1: operation 2
Subsystem 3: operation 5

Examples

Here are a few examples of Facade pattern in TypeScript-

Example #1: Travel Plan

In this example we have some classes which are responsible for handling different part of the travel-

  • Car – responsible for operating the car.
  • Direction – responsible for giving location/direction related information.
  • Toll – handles toll related actions.
  • Weather – gives weather information.

We are going to define a facade, and manage all required functionality from the facade.

Car Class [subsystem class]

  • Create file “car.ts”.
  • Create class “Car”.
// car.ts

class Car {
    startEngine(): void {
        console.log("Start Engine");
    }

    stopEngine(): void {
        console.log("Stop Engine");
    }

    goStraight(): void {
        console.log("Go Straight: ↑");
    }

    goLeft(): void {
        console.log("Go Left: ←");
    }

    goRight(): void {
        console.log("Go Right: →");
    }

    getDistanceTravelled(): number {
        // This is some random calculation for demo purpose
        return ((Math.random() * ((10000 - 100) * 10 + 1)) + 100 * 10) / 10.0;
    }
}

export default Car;

Point Class [general class]

Create a class for representing the coordinates of a point. This has props for latitude(lat) and longitude(lng).

// point.ts

class Point {
    private lat: number;
    private lng: number;
    
    constructor(lat: number, lng: number) {
        this.lat = lat;
        this.lng = lng;
    }

    getLat(): number {
        return this.lat;
    }

    getLng(): number {
        return this.lng;
    }
}

export default Point;

Direction Class [subsystem class]

  • Create file “direction.ts”.
  • Create class “Direction”.
// direction.ts

import Point from "./point";

class Direction {
    private startLat: number;
    private startLng: number;
    private endLat: number;
    private endLng: number;

    constructor(startLat: number, startLng: number, endLat: number, endLng: number) {
        this.startLat = startLat;
        this.startLng = startLng;
        this.endLat = endLat;
        this.endLng = endLng;
    }

    public getLocationDetails(lat: number, lng: number) {
        console.log("Country: ABC");
        console.log("City: DEF");
        console.log("State: GHI");
        console.log("Zip: 101010");
    }

    getCurrentLocation(): Point {
        // This is some random calculation for demo purpose
        const currentLat = (Math.random() * ((90 - (-90) * 10 + 1) - 90 * 10)) / 10.0;
        const currentLng = (Math.random() * ((180 - (-180) * 10 + 1) - 180 * 10)) / 10.0;

        return new Point(currentLat, currentLng);
    }

    getNextMove(): string {
        // This is some random calculation for demo purpose
        const nextMoves = ["straight", "left", "right"];
        return nextMoves[Math.floor(Math.random() * nextMoves.length)];
    }

    getFullRoute(): Point[] {
        const points: Point[] = [];

        for (let i = 0; i < 10; i++) {
            // This is some random calculation for demo purpose
            const currentLat = (Math.random() * ((90 - (-90) * 10 + 1) - 90 * 10)) / 10.0;
            const currentLng = (Math.random() * ((180 - (-180) * 10 + 1) - 180 * 10)) / 10.0;

            points[i] = new Point(currentLat, currentLng);
        }

        return points;
    }
}

export default Direction;

Toll Class [subsystem class]

  • Create file “toll.ts”.
  • Create class “Toll”.
// toll.ts

import Point from "./point";

class Toll {
    getTollPoints(lat: number, lng: number): Point[] {
        const points: Point[] = [];

        for (let i = 0; i < 10; i++) {
            // This is some random calculation for demo purpose
            const currentLat = (Math.random() * ((90 - (-90) * 10 + 1) - 90 * 10)) / 10.0;
            const currentLng = (Math.random() * ((180 - (-180) * 10 + 1) - 180 * 10)) / 10.0;

            points[i] = new Point(currentLat, currentLng);
        }

        return points;
    }

    getTollAmount(tollPointId: number): number {
        // This is some random calculation for demo purpose
        return (Math.random() * (((100 - 1) * 10 + 1)) + 10) / 10.0;
    }

    getTotalToll(lat: number, lng: number): number {
        // This is some random calculation for demo purpose
        return (Math.random() * (((100 - 1) * 10 + 1)) + 10) / 10.0;
    }
}

export default Toll;

Weather Class [subsystem class]

  • Create file “weather.ts”.
  • Create class “Weather”.
// weather.ts

class Weather {
    getWeatherInfo(lat: number, lng: number): void {
        console.log("Temperature: 20.7");
        console.log("Precipitation: 1%");
        console.log("Humidity: 73%");
        console.log("Wind: 8 km/h");
    }
}

export default Weather;

Facade Class

This travel facade contains the functionality required by the client.

  • Create file “travel-facade.ts”.
  • Create class “TravelFacade”.
  • Define private properties for objects of type “Car”, “Toll”, “Weather”, and “Direction”.
  • In the constructor initialize the objects.
  • Declare methods as per requirement of the client, and in the method implementations use/call the methods from the subsystem(Car, Weather, Toll, Direction) classes.
// travel-facade.ts

import Car from "./car";
import Direction from "./direction";
import Point from "./point";
import Toll from "./toll";
import Weather from "./weather";


class TravelFacade {
    private startLat: number;
    private startLng: number;

    private endLat: number;
    private endLng: number;

    private direction: Direction;
    private toll: Toll;
    private car: Car;
    private weather: Weather;

    // define constructor
    constructor(startLat: number, startLng: number, endLat: number, endLng: number) {
        this.startLat = startLat;
        this.startLng = startLng;
        this.endLat = endLat;
        this.endLng = endLng;

        // Initialize classes
        this.direction = new Direction(startLat, startLng, endLat, endLng);
        this.car = new Car();
        this.toll = new Toll();
        this.weather = new Weather();
    }

    getRoute(): Point[] {
        return this.direction.getFullRoute();
    }

    getLocationInfo(lat: number, lng: number) {
        this.direction.getLocationDetails(lat, lng);
        this.weather.getWeatherInfo(lat, lng);
    }

    getCurrentLocation(): Point {
        return this.direction.getCurrentLocation();
    }

    operateCar(): void {
        const fullRoute = this.direction.getFullRoute();

        this.car.startEngine();

        for (let point of fullRoute) {
            const nextMove = this.direction.getNextMove();

            switch (nextMove) {
                case "straight": this.car.goStraight(); break;
                case "left": this.car.goLeft(); break;
                case "right": this.car.goRight(); break;
            }
        }

        this.car.stopEngine();
    }

    getTotalTollAmount(lat: number, lng: number) {
        console.log("Total Toll Amount: " + this.toll.getTotalToll(lat, lng));
    }

}

export default TravelFacade;

Demo

We can not initialize the facade and use the methods from that.

// demo.ts

import TravelFacade from "./travel-facade";

const travelFacade = new TravelFacade(10, 10, 20, 30);

const currentLocation = travelFacade.getCurrentLocation();

console.log("Current Latitude: " + currentLocation.getLat());
console.log("Current Longitude: " + currentLocation.getLng());


travelFacade.getLocationInfo(20, 30);

travelFacade.getTotalTollAmount(20, 30);

travelFacade.operateCar();

Output

Current Latitude: 3.360968867455751
Current Longitude: 15.476935275479192


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


Total Toll Amount: 6.488174883078076


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

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.