Observer Design Pattern - TypeScript
Weather Monitoring - Realtime Display
Congratulations ! You have been given a contract from Weather Monitoring company to proivde a software.
Requirement
You need to provide following three types of displays.
- Current Conditions
- Weather Statistics
- Simple Forecast
They provide you a library/ api which you can use to get the Weather Data.
The library knows how to talk to real weather monitoring station (physical device) and get weather data, you do not need to worry about it.
The library provides following Class/ Object.
WeatherData {
private getTemperature();
private getHumidity();
private getPressure();
public measurementsChanged();
}
Private methods are used to get the latest weather data by talking to physical station. Method measurementsChanged()
gets called when there is new weather data (we don't need to know how this method gets called). Method measurementsChanged()
is public, meaning we have access to this method.
Currently there are three displays but there is going to be more in the future, so we should be able to add new displays with less or no code update in WeatherData.
Approach - 1: Coding into the library
If we take the approach of writing code directly into the library method measurementsChanged()
then we will be creating tight coupling between the library and our display Classes.
Sample Code:
WeathreData {
...
public measurementsChanged() {
const temperature = this.getTemperature();
const humidity = this.getHumidity();
const pressure = this.getPressure();
currentConditions.update(temperature, humidity, pressure);
statistics.update(temperature, humidity, pressure);
forecast.update(temperature, humidity, pressure);
}
}
If we take the above approach, then adding another type of display requires adding code into the library. And also we can't add more displays at run time.
Approach - 2: Using TypeScript Interfaces, Push Data
As we know, using interfaces will produce loosely coupled code. Lets propose the followinng approach using interfaces.
We propose two interfaces, one for us and one for the company to implement.
Observable
interface to be implemented byWeatherData
, which is provided by the company.Observer
interface implemented by various display classes, which we are going to develop.
Observer
interface has one method update()
. WeatherData will call this method whenever there is new data.
WeatherData class which is provided by the company will implement interface Observable
. By implementing this interface:
WeatherData can work with the display classes without knowing internal workings of Displays
We will be able to add or remove displays at run time
Adding a new type of display does not require any modification to the WeatherData class.
Changes to either WeatherData or display classes do not affect each other, as long as they comply with interfaces
Install and Run
Clone my GitHub repository -
git clone git@github.com:smarigowda/observer-pattern-weatherdata-typescript.git
Checkout the push branch -
git checkout push-approach
Install node modules -
yarn
ornpm install
Run the test program -
npm run test
Approach - 3: Using TypeScript Interfaces, Pull Data
In the previous push
approach, WeatherData is pushing the data to observers (various displays)
What if there is a new data like for ex: Wind Speed
added to Weather Data and one of the new Display need that data ? Then we need to add this new data type to Observer interface and we need to modify all the implementations (Displays). So push
approach is not a flexible design. Lets update the design so that observers can pull the data from WeatherData. This way observers can pull only the data which they need and also when a new data type is added by WeatherData we do not need to modify existing observers.
Link to github commit:
As you can see, changes needed are:
We exposed the methods inside WeatherData for Observers to pull the weather data.
Observable interface updated to include public methods.
Observer interface is updated to remove the weather data which was provided in
update()
method.All the display classes updated to match the interface.
Added a new type of weather data -
WindSpeed
Now if we add another display type say Wind Speed Display then we do not need any changes to existing displays or Observer interface, we can just create a new class and pull only the WindSpeed from Weather Data observable.
Link to github commit - Wind Speed display added:
Install and Run
Clone my GitHub repository -
git clone git@github.com:smarigowda/observer-pattern-weatherdata-typescript.git
Checkout the pull approach branch -
git checkout pull-approach
Install node modules -
yarn
ornpm install
Run the test program -
npm run test