In previous tutorial we created a simple navigator with strategy design pattern but now we are going to add some new functions to make it more sensible.

Simple Navigator

In advance Navigator each strategy has it’s own formula to calculate time for reaching destination and also they may have some common functions like estimatedTimeText function that just prints calculated time and structure of printed message is same for all strategies.

we used module to prevent name conflicts with Simple Navigator

export module AdvanceNavigator {
    export interface SimpleLocation {
        latitude: number
        longitude: number
    }
    
    interface EstimatedTime {
        minutes: number,
        hours: number
    }
    
    interface Strategy {
        findRoute(A: SimpleLocation, B:SimpleLocation)
        estimateTime(distance: number): EstimatedTime
    }
    
    export class NavigatorContext  {
        strategy: Strategy;
    
        setStrategy(strategy: Strategy) {
            this.strategy = strategy
        }
    
        findRoute(A: SimpleLocation, B: SimpleLocation) {
            return this.strategy.findRoute(A, B)
        }
    
        estimateTime(distance: number) {
            return this.strategy.estimateTime(distance)
        }
    
        findDistance(A: SimpleLocation, B: SimpleLocation) {
            let radlat1 = Math.PI * A.latitude/180;
            let radlat2 = Math.PI * B.latitude/180;
            let theta = A.longitude - B.longitude;
            let radtheta = Math.PI * theta/180;
            let dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
            if (dist > 1) {
                dist = 1;
            }
            dist = Math.acos(dist);
            dist = dist * 180/Math.PI;
            dist = dist * 60 * 1.1515;
            dist = dist * 1.609344
            return parseFloat(dist.toPrecision(2));
        }
    
        estimatedTimeText(estimatedTime: EstimatedTime): string {
            let text = '';
            text += estimatedTime.hours ? ` ${estimatedTime.hours} hours ` : ``
            text += estimatedTime.minutes ? ` ${estimatedTime.minutes} minutes ` : ``
            return text
        }
    }
    
    export class WalkingStrategy extends NavigatorContext implements Strategy {
        findRoute(A: SimpleLocation, B: SimpleLocation) {
            const distance = this.findDistance(A, B);
            const estimatedTime = this.estimateTime(distance)
            return `You will walk ${distance * 1000} M, Estimated time is ${this.estimatedTimeText(estimatedTime)}`
        }
    
        estimateTime(distance: number): EstimatedTime {
            const totalMinutes = Math.ceil((distance * 1000) / 20) ;
            return {
                minutes: totalMinutes % 60,
                hours: Math.floor(totalMinutes / 60)
            }
        }
    
    }
    
    
    export class CarStrategy extends NavigatorContext implements Strategy {
        findRoute(A: SimpleLocation, B: SimpleLocation) {
            const distance = this.findDistance(A, B);
            let estimatedTime = this.estimateTime(distance)
            return `You will Drive ${distance * 1000} M, Estimated time is ${this.estimatedTimeText(estimatedTime)}`
        }

        estimateTime(distance: number): EstimatedTime {
            const totalMinutes = Math.ceil((distance * 1000) / 105) ;
            return {
                minutes: totalMinutes % 60,
                hours: Math.floor(totalMinutes / 60)
            }
        }
    
    }
   
   
}

Let’s how to use

Usage is same as Simple Navigator

import { AdvanceNavigator } from './Advance'


/* Advance Navigation */
const advanceWalkingStrategy = new AdvanceNavigator.WalkingStrategy()

const advanceCarStrategy = new AdvanceNavigator.CarStrategy();

const advanceNavigatorContext = new AdvanceNavigator.NavigatorContext;


const GasStation: AdvanceNavigator.SimpleLocation = {
    latitude: 47.101563,
    longitude: 25.410596
};

const NationalPark: AdvanceNavigator.SimpleLocation = {
    latitude: 47.101504,
    longitude: 25.399015
};

advanceNavigatorContext.setStrategy(advanceWalkingStrategy);
result = advanceNavigatorContext.findRoute(GasStation, NationalPark);
console.log(result);
// You will walk 880 M, Estimated time is  44 minutes

advanceNavigatorContext.setStrategy(advanceCarStrategy);
result = advanceNavigatorContext.findRoute(NationalPark, GasStation);
console.log(result);
// You will Drive 880 M, Estimated time is  9 minutes

You can get the source code in Github Repo

https://github.com/mrfarhadir/design-patterns/blob/master/Strategy/Navigator/Advance.ts

Leave your thoughts