Observer Pattern | Set 2 (Implementation)

12 Feb, 2018
We strongly recommend to refer below Set 1 before moving on to this post.
Observer Pattern -Introduction
In Set 1, we discussed below problem, a solution for the problem without Observer pattern and problems with the solution.
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
Applying Observer pattern to above problem:Let us see how we can improve the design of our application using observer pattern. If we observe the flow of data we can easily see that the CricketData and display elements follow subject-observers relationship.
New Class Diagram: 
Java Implementation:
// Java program to demonstrate working of// onserver patternimport java.util.ArrayList;import java.util.Iterator;  // Implemented by Cricket data to communicate// with observersinterface Subject{    public void registerObserver(Observer o);    public void unregisterObserver(Observer o);    public void notifyObservers();}  class CricketData implements Subject{    int runs;    int wickets;    float overs;    ArrayList<Observer> observerList;      public CricketData() {        observerList = new ArrayList<Observer>();    }      @Override    public void registerObserver(Observer o) {        observerList.add(o);    }      @Override    public void unregisterObserver(Observer o) {        observerList.remove(observerList.indexOf(o));    }      @Override    public void notifyObservers()    {        for (Iterator<Observer> it =              observerList.iterator(); it.hasNext();)        {            Observer o = it.next();            o.update(runs,wickets,overs);        }    }      // 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 90 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();          notifyObservers();    }}  // This interface is implemented by all those// classes that are to be updated whenever there// is an update from CricketDatainterface Observer{    public void update(int runs, int wickets,                      float overs);}  class AverageScoreDisplay implements Observer{    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);    }}  class CurrentScoreDisplay implements Observer{    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 Classclass 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();          // register display elements        cricketData.registerObserver(averageScoreDisplay);        cricketData.registerObserver(currentScoreDisplay);          // in real app you would have some logic to        // call this function when data changes        cricketData.dataChanged();          //remove an observer        cricketData.unregisterObserver(averageScoreDisplay);          // now only currentScoreDisplay gets the        // notification        cricketData.dataChanged();    }}
Output:
Average Score Display: 
Run Rate: 8.823529
PredictedScore: 441

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

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


Note: Now we can add/delete as many observers without changing the subject.
References:
https://en.wikipedia.org/wiki/Observer_patternHead First Design Patterns book (highly recommended)
https://en.wikipedia.org/wiki/Observer_pattern
Head First Design Patterns book (highly recommended)
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 contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above
Design Pattern
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Factory method design pattern in Java
Builder Design Pattern
Unified Modeling Language (UML) | An Introduction
MVC Design Pattern
Introduction of Programming Paradigms
Abstract Factory Pattern
Monolithic vs Microservices architecture
Composite Design Pattern
Unified Modeling Language (UML) | Activity Diagrams
Unified Modeling Language (UML) | State Diagrams