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