Skip to main content

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.

Observer Patten

We propose two interfaces, one for us and one for the company to implement.

  1. Observable interface to be implemented by WeatherData, which is provided by the company.
  2. 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 or npm install

  • Run the test program - npm run test

Observer Patten Output

Approach - 3: Using TypeScript Interfaces, Pull Data

In the previous push approach, WeatherData is pushing the data to observers (various displays)

Push Approach

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:

https://github.com/smarigowda/observer-pattern-weatherdata-typescript/commit/876e448b4c46c09998d5120a12ab146440ef7d1c

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

Data getter methods exposed to public

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:

https://github.com/smarigowda/observer-pattern-weatherdata-typescript/commit/9a79eca0fb6e01b214ee05f6eb8c8fbe01b498fb

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 or npm install

  • Run the test program - npm run test

Pull Approach Output