Previous Lecture Lecture 12 Next Lecture

Lecture 12, Mon 05/13

Design Patterns - Observer

Observer Pattern

ObserverOverview

ObserverUML

Example: Live updates for a hockey game

HockeyUMLObserver

Implementation

// Subject.java
public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}
// Observer.java
public interface Observer {
    public void update(String homeTeam, String awayTeam, 
                Pair<Integer, Integer> score,
                Pair<Integer, Integer> assists,
                String time);
}
// Display.java
public interface Display {
    public void display(); // displays the data
}
// Pair.java
// From generics lecture...
public class Pair<T,U> {
    private T first;
    private U second;

    public Pair(T first, U second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() { return first; }

    public U getSecond() { return second; }

    public void print() {
        System.out.println(first + ", " + second);
    }
}
// GameData.java
import java.util.ArrayList;

// Subject other observers will subscribe to
public class GameData implements Subject {

    private ArrayList<Observer> observers;
    private String homeTeam;
    private String awayTeam;
    private Pair<Integer, Integer> goals;
    private Pair<Integer, Integer> assists;
    private String time;
    
    public GameData(String homeTeam, String awayTeam) {
        observers = new ArrayList<Observer>();
        this.homeTeam = homeTeam;
        this.awayTeam = awayTeam;
        this.goals = new Pair<Integer, Integer>(0,0);
        this.assists = new Pair<Integer, Integer>(0,0);
        this.time = "";
    }
    
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) { // it exists
            observers.remove(i);
        }
    }
}
    @Override
    public void notifyObservers() {
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = observers.get(i);
            observer.update(homeTeam, awayTeam, goals, assists, time);
        }
    }
    
    public void updateGameState(Pair<Integer, Integer> goals,
            Pair<Integer, Integer> assists, String time) {
        this.goals = goals;
        this.assists = assists;
        this.time = time;
        notifyObservers();
    }
}
// GameObserver.java
public class GameObserver implements Observer, Display {

    private String homeTeam;
    private String awayTeam;
    private Pair<Integer, Integer> goals;
    private Pair<Integer, Integer> assists;
    private String time;
    
    public GameObserver(Subject gameData) {
        gameData = gameData;
        gameData.registerObserver(this);
    }
    
    @Override
    public void update(String homeTeam, String awayTeam,
            Pair<Integer, Integer> goals, Pair<Integer, Integer> assists,
            String time) {
        this.homeTeam = homeTeam;
        this.awayTeam = awayTeam;
        this.goals = goals;
        this.assists = assists;
        this.time = time;
        
        display();
    }

    @Override
    public void display() {
        System.out.format("%8s %-10s %-10s\n", "", homeTeam, awayTeam);
        System.out.format("%8s %-10d %-10d\n", "GOALS:", goals.getFirst(), goals.getSecond());
        System.out.format("%8s %-10d %-10d\n", "ASSISTS:", assists.getFirst(), assists.getSecond());
        System.out.format("%8s %-10s\n", "TIME:", time);
        System.out.println("----");
    }
}
// Lecture.java
import java.time.format.DateTimeFormatter;  
import java.time.LocalDateTime;  

public class Lecture {
    
    public static void main(String[] args) throws InterruptedException {

        GameData gameData = new GameData("Sharks", "Blues");
        
        // register Observer in constructor
        GameObserver gameObserver = new GameObserver(gameData);
        
        // set current time format
        DateTimeFormatter currentTime = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        LocalDateTime now = LocalDateTime.now();
        
        // Update game state
        gameData.updateGameState(new Pair<Integer, Integer>(0,1),
                                new Pair<Integer, Integer>(0,0),
                                currentTime.format(now));
        
        Thread.sleep(10000); // sleep for 10 seconds
        now = LocalDateTime.now();
        
        // Update game state
        gameData.updateGameState(new Pair<Integer, Integer>(1,1),
                new Pair<Integer, Integer>(1,0),
                currentTime.format(now));
        
        // remove observer
        gameData.removeObserver(gameObserver);
        
        Thread.sleep(5000); // sleep for 5 seconds
        now = LocalDateTime.now();
        
        gameData.updateGameState(new Pair<Integer, Integer>(1,2),
                new Pair<Integer, Integer>(1,1),
                currentTime.format(now));
        
        // re-register observer
        gameData.registerObserver(gameObserver);
        
        Thread.sleep(5000); // sleep for 5 seconds
        now = LocalDateTime.now();
        
        gameData.updateGameState(new Pair<Integer, Integer>(2,2),
                new Pair<Integer, Integer>(2,1),
                currentTime.format(now));
        
        System.out.println("Exiting");
    }
}