Observer Pattern | Set 1 (Introduction)

• Difficulty Level : Medium
• Last Updated : 01 Sep, 2021

Let us first consider the following scenario to understand observer pattern.

Scenario:

Suppose we are building a cricket app that notifies viewers about the information such as current score, run rate etc. Suppose we have made two display elements CurrentScoreDisplay and AverageScoreDisplay. CricketData has all the data (runs, bowls etc.) and whenever data changes the display elements are notified with new data and they display the latest data accordingly.

Below is the java implementation of this design.

 `// Java implementation of above design for Cricket App. The ` `// problems with this design are discussed below. ` ` `  `// A class that gets information from stadium and notifies ` `// display elements, CurrentScoreDisplay & AverageScoreDisplay ` `class` `CricketData ` `{ ` `    ``int` `runs, wickets; ` `    ``float` `overs; ` `    ``CurrentScoreDisplay currentScoreDisplay; ` `    ``AverageScoreDisplay averageScoreDisplay; ` ` `  `    ``// Constructor ` `    ``public` `CricketData(CurrentScoreDisplay currentScoreDisplay, ` `                       ``AverageScoreDisplay averageScoreDisplay) ` `    ``{ ` `        ``this``.currentScoreDisplay = currentScoreDisplay; ` `        ``this``.averageScoreDisplay = averageScoreDisplay; ` `    ``} ` ` `  `    ``// Get latest runs from stadium ` `    ``private` `int` `getLatestRuns() ` `    ``{ ` `        ``// return 90 for simplicity ` `        ``return` `90``; ` `    ``} ` ` `  `    ``// Get latest wickets from stadium ` `    ``private` `int` `getLatestWickets() ` `    ``{ ` `        ``// return 2 for simplicity ` `        ``return` `2``; ` `    ``} ` ` `  `    ``// Get latest overs from stadium ` `    ``private` `float` `getLatestOvers() ` `    ``{ ` `        ``// return 10.2 for simplicity ` `        ``return` `(``float``)``10.2``; ` `    ``} ` ` `  `    ``// This method is used update displays when data changes ` `    ``public` `void` `dataChanged() ` `    ``{ ` `        ``// get latest data ` `        ``runs = getLatestRuns(); ` `        ``wickets = getLatestWickets(); ` `        ``overs = getLatestOvers(); ` ` `  `        ``currentScoreDisplay.update(runs,wickets,overs); ` `        ``averageScoreDisplay.update(runs,wickets,overs); ` `    ``} ` `} ` ` `  `// A class to display average score. Data of this class is ` `// updated by CricketData ` `class` `AverageScoreDisplay ` `{ ` `    ``private` `float` `runRate; ` `    ``private` `int` `predictedScore; ` ` `  `    ``public` `void` `update(``int` `runs, ``int` `wickets, ``float` `overs) ` `    ``{ ` `        ``this``.runRate = (``float``)runs/overs; ` `        ``this``.predictedScore = (``int``) (``this``.runRate * ``50``); ` `        ``display(); ` `    ``} ` ` `  `    ``public` `void` `display() ` `    ``{ ` `        ``System.out.println(``"\nAverage Score Display:\n"` `+ ` `                           ``"Run Rate: "` `+ runRate + ` `                           ``"\nPredictedScore: "` `+ predictedScore); ` `    ``} ` `} ` ` `  `// A class to display score. Data of this class is ` `// updated by CricketData ` `class` `CurrentScoreDisplay ` `{ ` `    ``private` `int` `runs, wickets; ` `    ``private` `float` `overs; ` ` `  `    ``public` `void` `update(``int` `runs,``int` `wickets,``float` `overs) ` `    ``{ ` `        ``this``.runs = runs; ` `        ``this``.wickets = wickets; ` `        ``this``.overs = overs; ` `        ``display(); ` `    ``} ` ` `  `    ``public` `void` `display() ` `    ``{ ` `        ``System.out.println(``"\nCurrent Score Display: \n"` `+ ` `                           ``"Runs: "` `+ runs +``"\nWickets:"` `                           ``+ wickets + ``"\nOvers: "` `+ overs ); ` `    ``} ` `} ` ` `  `// Driver class ` `class` `Main ` `{ ` `    ``public` `static` `void` `main(String args[]) ` `    ``{ ` `        ``// Create objects for testing ` `        ``AverageScoreDisplay averageScoreDisplay = ` `                                       ``new` `AverageScoreDisplay(); ` `        ``CurrentScoreDisplay currentScoreDisplay = ` `                                       ``new` `CurrentScoreDisplay(); ` ` `  `        ``// Pass the displays to Cricket data ` `        ``CricketData cricketData = ``new` `CricketData(currentScoreDisplay, ` `                                                  ``averageScoreDisplay); ` ` `  `        ``// In real app you would have some logic to call this ` `        ``// function when data changes ` `        ``cricketData.dataChanged(); ` `    ``} ` `} `

Output:

```Current Score Display:
Runs: 90
Wickets:2
Overs: 10.2

Average Score Display:
Run Rate: 8.823529
PredictedScore: 441```

Problems with above design:

• CricketData holds references to concrete display element objects even though it needs to call only the update method of these objects. It has access to too much additional information than it requires.
• This statement “currentScoreDisplay.update(runs,wickets,overs);” violates one of the most important design principle “Program to interfaces, not implementations.” as we are using concrete objects to share data rather than abstract interfaces.
• CricketData and display elements are tightly coupled.
• If in future another requirement comes in and we need another display element to be added we need to make changes to the non-varying part of our code(CricketData). This is definitely not a good design practice and application might not be able to handle changes and not easy to maintain.

How to avoid these problems?
Use Observer Pattern

Observer pattern

To understand observer pattern, first you need to understand the subject and observer objects.

The relation between subject and observer can easily be understood as an analogy to magazine subscription.

• A magazine publisher(subject) is in the business and publishes magazines (data).
• If you(user of data/observer) are interested in the magazine you subscribe(register), and if a new edition is published it gets delivered to you.
• If you unsubscribe(unregister) you stop getting new editions.
• Publisher doesn’t know who you are and how you use the magazine, it just delivers it to you because you are a subscriber(loose coupling).

Definition:

The Observer Pattern defines a one to many dependency between objects so that one object changes state, all of its dependents are notified and updated automatically.

Explanation:

• One to many dependency is between Subject(One) and Observer(Many).
• There is dependency as Observers themselves don’t have access to data. They are dependent on Subject to provide them data.

Class diagram:

Image Source : Wikipedia

• Here Observer and Subject are interfaces(can be any abstract super type not necessarily java interface).
• All observers who need the data need to implement observer interface.
• notify() method in observer interface defines the action to be taken when the subject provides it data.
• The subject maintains an observerCollection which is simply the list of currently registered(subscribed) observers.
• registerObserver(observer) and unregisterObserver(observer) are methods to add and remove observers respectively.
• notifyObservers() is called when the data is changed and the observers need to be supplied with new data.

Provides a loosely coupled design between objects that interact. Loosely coupled objects are flexible with changing requirements. Here loose coupling means that the interacting objects should have less information about each other.

Observer pattern provides this loose coupling as:

• Subject only knows that observer implement Observer interface.Nothing more.
• There is no need to modify Subject to add or remove observers.
• We can reuse subject and observer classes independently of each other.

When to use this pattern?
You should consider using this pattern in your application when multiple objects are dependent on the state of one object as it provides a neat and well tested design for the same.

Real Life Uses:

• It is heavily used in GUI toolkits and event listener. In java the button(subject) and onClickListener(observer) are modelled with observer pattern.
• All users of an app on play store gets notified if there is an update.

Observer Pattern | Set 2 (Implementation)

Further Read – Observer Method in Python

This article is contributed by Sulabh Kumar. If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.