The Observer Pattern in Java

Introduction to the Observer Pattern

Design pattern in a simple meaning, is a way to design reusable object-oriented code. We can think of ways to design our classes, interfaces, enums and their members so that the code is reusable but flexible.

There are 23 most important design patterns, pioneered by the book Design Patterns: Elements of Reusable Object-Oriented Software, written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides or Gang of Four for short. We will cover these design pattern one by one.

The Observer pattern defines a one-to-many between objects so that when one object (the subject or the publisher) changes state, all its dependents (the observers or the subscribers) are notified of changes and updated automatically.

Implementation of Observer Pattern in Java

The Observer pattern is very straightforward, say we want to live-update the score of a football match. The data will be randomly created but each time the score is updated, the new score will be output to screen. First we create the Subscriber interface, this interface defines the action should be done by all Subscribers:

public interface Subscriber {
    void update(String firstTeam,
                int scoreFirstTeam,
                String secondTeam,
                int scoreSecondTeam);
}

Then we create the Publisher interface in src folder like this:

public interface Publisher {
    void registerObserver(Subscriber subscriber);
    void removeObserver(Subscriber subscriber);
    void notifyObservers();
}

Next we create a concrete class of Subscriber interface, it just output the updated score to screen, the Display.java in src folder:

public class Display implements Subscriber{
  public void update(String firstTeam,
                     int scoreFirstTeam,
                     String secondTeam,
                     int scoreSecondTeam){
    System.out.print(firstTeam + ": "
        + scoreFirstTeam + " - ");
    System.out.print(secondTeam + ": "
        + scoreSecondTeam +"\n");
  }
}

Now we must create a concrete Publisher, which is the LiveScore class:

import java.util.ArrayList;
public class LiveScore implements Publisher {
  private final ArrayList<Subscriber> subs;
  private final String firstTeam;
  private int scoreFirstTeam;
  private final String secondTeam;
  private int scoreSecondTeam;
  public LiveScore(String firstTeam, String secondTeam){
    this.firstTeam = firstTeam;
    this.secondTeam = secondTeam;
    subs = new ArrayList<>();
  }
  public void registerSub(Subscriber sub) {
    subs.add(sub);
  }
  public void removeSub(Subscriber sub) {
    subs.remove(sub);
  }
  public void notifySub() {
    for (Subscriber sub: subs){
      sub.update(firstTeam, scoreFirstTeam,
          secondTeam, scoreSecondTeam);
    }
  }
  //faking live update so the score will be
  //notified to all subscribers
  public void fakeUpdate(){
    for (int i = 0; i < 10; i++){
      try{
        //create a random score
        scoreFirstTeam = Math.random() >= 0.7 ?
            scoreFirstTeam + 1 : scoreFirstTeam;
        scoreSecondTeam = Math.random() >= 0.7 ?
            scoreSecondTeam + 1 : scoreSecondTeam;
        //notify subscribers
        notifySub();
        //sleep for 1 sec
        Thread.sleep(1000);
      }catch (InterruptedException e){}
    }
  }
}

The publisher can add a subscriber, remove a subscriber and notify all subscribers. The method fakeUpdate() is to fake live data update :D. Now in Test.java:

public class Test {
  public static void main(String[] args){
    //create the publisher
    LiveScore live = new LiveScore("Man", "Liv");
    //create the subscriber
    Display display = new Display();
    //register the subscriber
    live.registerSub(display);
    //call fakeUpdate method to fake score update
    live.fakeUpdate();
  }
}

Run the code and we will see that the code outputs ten lines of score result , each second a line is output (the score is random, it does not express any score in real life. So to all the fans, please be calm). Here is a version of the output:

Man: 0 - Liv: 0
Man: 0 - Liv: 1
Man: 0 - Liv: 1
Man: 0 - Liv: 1
Man: 0 - Liv: 1
Man: 1 - Liv: 2
Man: 1 - Liv: 2
Man: 2 - Liv: 2
Man: 3 - Liv: 3
Man: 3 - Liv: 3

Leave a Reply