You are on page 1of 10

Observer Pattern

Observer Pattern
The Observer Pattern keeps your objects informed when something they might care
about happens. Objects can even decide at run time whether they want to be kept
informed. The Observer pattern is one of the most heavily used patterns in the JDK
or .NET FCL, and it is very useful. We will also look at one to many relationships and
loose coupling .

Case Study - The Car Dashboard Application


The three players in the system are the Car Dashboard that acquires the actual engine
data, the EngineData object that tracks the data coming from the Engine and updates the
displays, and the display that shows users the current conditions.

!
The EngineData object knows how to talk to the physical Engine, to get updated data.
The EngineData object then updates its displays for the three different display elements:
Analog Display (shows temperature, rpm, and speed), Digital Display, and a simple
gauge.

Project Requirements
1. Our job is to create an app that uses the EngineData object to update the three
displays for analog display, digital display, and a gauge. These displays must be

Page 1 of 10

Observer Pattern

updated each time EngineData has new measurements.


2. The EngineData class already exists, it has getter methods for three measurent
values: temperature. speed and rpm. And we need to implement
MeasurementChanged() so that it updates the three displays for analog display,
digital display, and gauge.
3. The measurementsChanged() method is called any time new engine measurement
data is available,
4. The system must be expandable - other developers can create new custom
displays and user can add or remove as many displays as they want to the
application.

public class EngineData


{
public void measurementsChanged()
{
float temp = getTemperature();
float rpm = getRPM();
float speed = getSpeed();
analogDisplay.update(temp, rpm, speed);
digitalDisplay.update(temp, rpm, speed);
gaugeDisplay.update(temp, rpm, speed);
}
}

The above code has design problems

1. By coding to concrete implementations we have no way to add or remove other


displays without making changes to program
2. The displays seem to have a common interface that has an update() method takes
the temp, humidity, and pressure values.

The Observer Pattern


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

Observer Pattern = Publisher + Subscriber

1. The SUBJECT likes a newspaper publisher begins publishing its newspaper.


2. The OBSERVER will subscribe to a particular publisher, and every time there's a
new edition it gets delivered to you. As long as your remain a subscriber.
3. You unsubscribe when you don't want newspaper anymore, and they stop being
delivered.

Page 2 of 10

Observer Pattern

!
There are few different ways to implement the Observer Pattern but most revolve around
a class design that includes Subject and Observer Interfaces.

Typical Class design for observer pattern

1. Subject interface : objects use this interface to register as observers and also to
remove themselves from being observers.
2. Observer interface : all potential observers need to implement the observer
interface. This interface just has one method, update() that gets called when the
subject's state changes.
3. Concrete subject ; implements the Subject interface. In addition to the register and
remove methods, the concrete subject implements a notifyObservers() method
that is used to update all the current observers whenever state changes.
4. The concrete subject may also have methods for setting and getting its state.
5. Concrete observers can be any class that implements the Observer interface.
Each observer registers with a concrete subject to receive updates.

Advantages
The subject is the sole owner of the data, the observers are dependent on the subject to
update them when the data changes. This leads to a good OO design than allowing
many objects to control the same data.

Page 3 of 10

Observer Pattern

Loose Coupling
When two objects are loosely coupled, they can interact, but have veryt little knowledge
of each other.
The Observer Pattern provides an object design where subjects and observers are
loosely coupled.
The Subject knows nothing about the observer except the Observer interface.
We can add new observers at any time. Likewise, we can remove observers at any
time.
We never need to modify the subject to add new types of observers.
We can reuse subjects or observers independently of each because they are not tightly
coupled.
Changes to either the subject or an observer will not affect the other.

Advantages of Loose Coupling


Allow us to build flexible OO systems that can handle change because they minimize
the interdependency between objects.

Practice
Implement the Car Dashboard App, the EngineData class and its display elements
using Class Diagrams.

Designing the Dashboard

!
Page 4 of 10

Observer Pattern


Implementing the Dashboard
public interface Subject
{
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}

public interface Observer


{
public void update(float temp, float rpm, float speed);
}

public interface DisplayElement


{
public void display();
}

Implementing the Subject interface in EngineData

public class EngineData implements Subject


{
private ArrayList<Observer> observers;
private float temperature;
private float rpm;
private float speed;

public EngineData()
{
observers = new ArrayList<Observer>();
}

@Override
public void registerObserver(Observer o)
{
observers.add(o);
}

@Override
public void removeObserver(Observer o)
{
int i = observers.indexOf(o);
Page 5 of 10

Observer Pattern
if (i >= 0)
observers.remove(i);
}

@Override
public void notifyObserver()
{
for (int i = 0; i < observers.size(); i++)
{
Observer observer = (Observer) observers.get(i);
observer.update(temperature, rpm, speed);
}
}

public void measurementsChanged()


{
notifyObserver();
}

public void setMeasurements(float temp, float rpm, float speed) {


this.temperature = temp;
this.rpm = rpm;
this.speed = speed;
measurementsChanged();
}
}


Building the display element
public class AnalogDisplay implements Observer, DisplayElement
{
private float temperature;
private float rpm;
private Subject engineData;

public AnalogDisplay(Subject engineData)


{
this.engineData = engineData;
engineData.registerObserver(this);
}

@Override
public void display()
{
System.out.println("Analog Display: "
+ temperature + "F degrees and "
Page 6 of 10

Observer Pattern
+ rpm + " revolutions per minute");
}

@Override
public void update(float temp, float rpm, float speed)
{
this.temperature = temp;
this.rpm = rpm;
display();
}
}


Power up your car
public class Dashboard
{
public static void main(String[] args)
{
EngineData engineData = new EngineData();

AnalogDisplay analog = new AnalogDisplay(engineData);


DigitalDisplay digital = new DigitalDisplay(engineData);

engineData.setMeasurements(80, 7000, 80);


engineData.setMeasurements(70, 5000, 70);
engineData.setMeasurements(60, 4000, 60);
}
}


OO Principles

1.
2.
3.
4.

Encapsulate what varies.


Favor composition over inheritance.
Program to inheritance not implementation
Strive for loosely coupled designs between objects that interact.

Using Java's built-in Observer Patter


Java has built-in support in server of its API. The most general is the Observer interface
and the Observable class in the java.util package. With these APIs, all you have to extend
Observable and tell it when to notify the Observers. The API does the rest for you.

Page 7 of 10

Observer Pattern

Observer interface

Aggregation

Observabke class

update()

addObservers()
delefeObservers()

Inheritance

notifyObservers()

Inheritance

setChanged()

Inheritance
CourseData class

Dean class

Professor class

update()

update()

display()

display()

getAttendance()
getTestScores()

CourseData.java
import java.util.Observable;

public class CourseData extends Observable {


private float attendance; // overall attendance in %
private float testScores; // overall test scores in %
public CourseData() {}
public void dataChanged() {
setChanged();
notifyObservers();
}

public void setData(float attendance, float testScores) {


this.attendance = attendance;
this.testScores = testScores;
dataChanged();
}
public float getAttendance() {
return attendance;
}
public float getTestScores() {
return testScores;
}

Page 8 of 10

Observer Pattern

Displayable.java
public interface Displayable {
public void display();
}

Dean.java
import java.util.Observable;
import java.util.Observer;

public class Dean implements Observer, Displayable {


Observable observable;
private float testScores;
public Dean(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable obs, Object arg) {
if (obs instanceof CourseData) {
CourseData data = (CourseData)obs;
this.testScores = data.getTestScores();
display();
}
}
@Override
public void display() {
if (testScores > 90 ) {
System.out.println("This class is doing fine. No action is required.");
} else if (testScores > 70 ) {
System.out.println("This class is not doing so well. The professor needs to pay
more attention");
} else {
System.out.println("This class has problems. We need to provide tutoring services
to students");
}
}
}

Page 9 of 10

Observer Pattern

Professor.java
import java.util.Observable;
import java.util.Observer;

public class Professor implements Observer, Displayable {


Observable observable;
private float attendance;
private float testScores;
public Professor(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable obs, Object arg) {
if (obs instanceof CourseData) {
CourseData data = (CourseData)obs;
this.attendance = data.getAttendance();
this.testScores = data.getTestScores();
display();
}
}
@Override
public void display() {
System.out.println("The class attendance = " + attendance + "%");
System.out.println("The class average scores = " + testScores + "%");
}
}


Dashboard.java
public class Dashboard {

public static void main(String[] args) {


CourseData data = new CourseData();
Dean dean = new Dean(data);
Professor prof = new Professor(data);
data.setData(98, 95);
data.setData(88, 75);
data.setData(78, 65);
}

Page 10 of 10

You might also like