23 - Observer
Tags: flutter, dart, oop, programming
Published: 2021-06-21 10:23:29

In the last article, I have analysed a behavioural design pattern that reduces dependencies between a set of interacting objects by decoupling the interaction logic from the objects and moving it to a dedicated controller — Mediator. In this article, I would like to analyse and implement another behavioural design pattern that lets you define a publish-subscribe mechanism to notify multiple objects about any events that happen to the object they’re subscribed to — it is Observer.

## Table of Contents

* What is the Observer design pattern?
* Analysis
* Implementation
* Your Contribution

## What is the Observer design pattern?

![Neale Donald Walsch Quote About The Observer Effect](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6d2efifmnas8vzuvppqz.jpeg)

**Observer**, also known as **Dependents** or **Publish-Subscribe**, belongs to the category of behavioural design patterns. The intention of this design pattern is described in the [GoF book](https://en.wikipedia.org/wiki/Design_Patterns):

> Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

**Spoiler alert**: if you have ever heard about reactive programming or even used the related frameworks/libraries/tools such as [ReactiveX](http://reactivex.io/), [RxDart](https://pub.dev/packages/rxdart) or just basic streams in Dart, this design pattern won’t be a game-changer to you. But it is still worth knowing how reactive programming ideas are implemented in the OOP context from the ground up, though.

The motivation for this design pattern comes from the problem of having a collection of tightly coupled objects in the system where changes for one object should trigger changes in the others (one-to-many relationship). An inflexible way to implement this is to define an object that implements updating the state of other dependent ones. Such object becomes hard to implement, maintain, test and reuse because of the dependency chaos.

A better way to approach this is to implement a publish-subscribe mechanism that sends the update events to dependent objects so they could implement and maintain the update logic on their own. To achieve this, the Observer design pattern introduces two roles: **Subject** and **Observer**.

The subject is the publisher of notifications that also defines a way for the observers to subscribe/unsubscribe from those notifications. A subject may have any number of dependent observers — the same idea of maintaining a one-to-many relationship just in a more flexible way. When a subject changes state, all registered observers are notified and updated automatically. This way the subject could trigger an update on dependent objects without even knowing who its observers are — this enables loose coupling between subject and observers.

Let’s move to the analysis and implementation parts to understand and learn the details about this pattern and how to implement it!

## Analysis

The general structure of the Observer design pattern looks like this:

![Observer Class Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hzwpgbxft8milgca6c9.png)

* *Publisher (Subject)* — provides an interface for attaching and detaching *Subscriber (Observer)* objects, contains a list of observers;
* *(Optional) Concrete Publishers* — stores state of interest for *Concrete Subscribers* and sends a notification to its observers when the state changes. This class is optional when only a single type of *Publisher* is needed. In such case, the state and notification logic is handled by the *Publisher*;
* *Subscriber (Observer)* — declares the notification interface for objects that should be notified of changes in a *Subject*;
* *Concrete Subscribers* — implements the *Subscriber (Observer)* interface to keep its state consistent with the subject’s state;
* *Client* — creates *Subject* and *Observer* objects, attaches observers to subject updates.

### Observer vs Mediator

If you have read the previous article in the series or are familiar with the Mediator design pattern you could feel some kind of *déjà vu* — isn’t the Observer design pattern the same thing? Let me explain.

The primary goal of the Mediator design pattern is to replace many-to-many relationships between objects with one-to-many relationship by using the dedicated mediator object that handles the communication part. Observer allows establishing a dynamic one-way connection between objects, where some objects act as subordinates of others.

If you have only one mediator that allows subscriptions to its state, this implementation is based on the Observer design pattern but the Mediator design pattern could be also used only as a part of the publish-subscribe communication. Now, if we have multiple publishers and multiple subscribers (which could be publishers as well), there won’t be any mediator object only a distributed set of observers.

### Applicability

The Observer design pattern should be used when a change to one object requires changing others, but you don’t know how many objects need to be changed and how. The pattern allows subscribing to such object events and changing the dependent object’s state accordingly.

Also, this pattern should be used when some objects must observe others, but only for a limited time. The subscription mechanism allows dependent objects to listen to the update events on demand and change this behaviour at run-time.

## Implementation

![Bring It On](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjuaohboq9ba03j4rbud.gif)

For the implementation part, we will use the Observer design pattern to implement a stock market prototype.

In the stock market, there are hundreds and thousands of different stocks. Of course, not all of them are relevant to you, so you would like to subscribe and track only the specific ones.

The prototype allows subscribing to 3 different stocks — GameStop (GME), Alphabet Inc. a.k.a. Google (GOOGL) and Tesla Motors (TSLA). Also, there are two different types of subscriptions:

* Default stock subscription — notifies about every subscribed stock change.
* Growing stock subscription — notifies only about the growing stock changes.

Such stocks’ tracker could be easily implemented by using the Observer design pattern. Of course, the prototype only supports 3 different stock types, but new stock tickers or even new subscription types could be easily added later on without affecting the existing code. Let’s check the class diagram first and then implement the pattern!

### Class diagram

The class diagram below shows the implementation of the Observer design pattern:

![Observer Implementation Class Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9dgva29llgzxlu3ocrs5.png)

*StockTicker* is an abstract class that is used as a base class for all the specific stock ticker classes. The class contains *title*, *stockTimer* and *stock* properties, *subscribers* list, provides several methods:

* *subscribe()* — subscribes to the stock ticker;
* *unsubscribe()* — unsubscribes from the stock ticker;
* *notifySubscribers()* — notifies subscribers about the stock change;
* *setStock()* — sets stock value;
* *stopTicker()* — stops ticker emitting stock events.

*GameStopStockTicker*, *GoogleStockTicker* and *TeslaStockTicker* are concrete stock ticker classes that extend the abstract class *StockTicker*.

*Stock* class contains *symbol*, *changeDirection*, *price* and *changeAmount* properties to store info about the stock.

*StockTickerSymbol* is an enumerator class defining supported stock ticker symbols — GME, GOOGL and TSLA.

*StockChangeDirection* is an enumerator class defining stock change directions — growing and falling.

*StockSubscriber* is an abstract class that is used as a base class for all the specific stock subscriber classes. The class contains *title*, *id* and *stockStreamController* properties, *stockStream* getter and defines the abstract *update()* method to update subscriber state.

*DefaultStockSubscriber* and *GrowingStockSubscriber* are concrete stock subscriber classes that extend the abstract class *StockSubscriber*.

### StockTicker

An abstract class implementing base methods for all the specific stock ticker classes. Property *title* is used in the UI for stock ticker selection, *stockTimer* periodically emits a new stock value that is stored in the *stock* property by using the *setStock()* method. The class also stores a list of stock subscribers that can subscribe to the stock ticker and unsubscribe from it by using the *subscribe()* and *unsubscribe()* respectively. Stock ticker subscribers are notified about the value change by calling the *notifySubscribers()* method. The stock timer could be stopped by calling the *stopTicker()* method.

![stock_ticker.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mn29r9r0zri2h4orarjo.png)

### Concrete stock ticker classes

All of the specific stock ticker classes extend the abstract *StockTicker* class.

* *GameStopStockTicker* — a stock ticker of the GameStop stocks that emits a new stock event every 2 seconds.

![gamestop_stock_ticker.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/blv3nc2h1fguiqgkp34z.png)

* *TeslaStockTicker* — a stock ticker of the Tesla stocks that emits a new stock event every 3 seconds.

![tesla_stock_ticker.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z12mpq12rnrmec9jfpsg.png)

* *GoogleStockTicker* — a stock ticker of the Google stocks that emits a new stock event every 5 seconds.

![google_stock_ticker.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbd3s7td1wgwtz4tcgqy.png)

### Stock

A simple class to store information about the stock. Stock class contains data about the stocker ticker symbol, stock change direction, current price and the change amount.

![stock.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6zprqkmp64j5yka90xq.png)

### StockTickerSymbol

A special kind of class — *enumeration* — to define supported stock ticker symbols. Also, there is a *StockTickerSymbolExtension* defined where the *toShortString()* method returns a short version of the enumeration string value.

![stock_ticker_symbol.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ambr8huzkj4ddgmjq9p.png)

### StockChangeDirection

A special kind of class — *enumeration* — to define stock change directions.

![stock_change_direction.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yilwp5t3w1x178jw3zfx.png)

### StockSubscriber

An abstract class containing base properties for all the specific stock ticker classes. Property *title* is used in the UI for stock subscriber selection, *id* uniquely identifies the subscriber. Updated stock values are added to the *stockStreamController* and emitted via the *stockStream*. Abstract method *update()* is defined and must be implemented by all the concrete stock subscriber classes.

![stock_subscriber.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dxqx5sn0xkqw934x0q3m.png)

### Concrete stock subscriber classes

* *DefaultStockSubscriber* — a default stock subscriber that emits every stock change on update.

![default_stock_subscriber.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8h7kqatklsymmkhnxu5e.png)

* *GrowingStockSubscriber* — a growing stock subscriber that emits only growing stock changes on update.

![growing_stock_subscriber.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pugeqvb98zk6b6tbb2a8.png)

### Example

First of all, a markdown file is prepared and provided as a pattern’s description:

![Observer Markdown](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oaaua58cxjt8t64lhv3v.gif)

*ObserverExample* contains a list of *StockSubscriber* as well as a list of *StockTickerModel* objects (specific *StockTicker* class with a flag of whether the user is subscribed to the stock ticker or not).

![observer_example.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nblt9l6t063g84ywtn9g.png)

A specific subscriber class could be easily changed by using the *StockSubscriberSelection* widget. Also, *StockTickerSelection* allows easily subscribe/unsubscribe from the specific stock ticker at run-time.

![Observer Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o69l10vy7hn2cay0c7ue.gif)

As you can see in the example, the subscription type could be easily changed at run-time, you could start and stop tracking of the specific stocks at any point as well.

All of the code changes for the Observer design pattern and its example implementation could be found [here](https://github.com/mkobuolys/flutter-design-patterns/pull/29).

## Your Contribution

💖 or 🦄 this article to show your support and motivate me to write better!
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.
📢 Share this article with your friends, colleagues on social media.
➕ Follow me on dev.to or any other social media platform.
⭐ Star the [Github](https://github.com/mkobuolys/flutter-design-patterns) repository.