Professional Documents
Culture Documents
Observer
Observer
KeepingyourObjectsintheKnow!
TheWeatherORama!
Current conditions is
one of three different
displays. The user can
also get weather stats
and a forecast.
Pulls data
Displays
Humidity Sensor
Device
Current
Conditions
Temp: 72
Humidity: 60
Pressure:
Temperature Sensor
Device
Weather Station
Display Device
Pressure Sensor
Device
Weather-O-Rama provides
What we implement
TheJob:CreateanappthatusestheWeatherDataobjecttoupdate
threedisplaysforcurrentconditions,weatherstats,andaforecast.
TheWeatherDataclass
These three methods return the most recent
weather measurements for temperature, humidity,
and pressure respectively.
WeatherData
getTemperature ( )
getHumidity ( )
getPressure ( )
measurementChanged ( )
// other methods
/*
A clue: what we need to add!
TheSpecssofar
TheWeatherDataclasshasgettermethodsforthree
measurementvalues:temperature, humidity,andpressure.
ThemeasurementsChanged()methodiscalledanytimenew
weathermeasurementdataisavailable.(Wedontknoworcare
howthismethodiscalled;wejustknowthatitis)
Weneedtoimplementthreedisplayelementsthatusetheweather
data:acurrentconditionsdisplay,astatisticsdisplay,anda
forecastdisplay.Thesedisplaysmustbeupdatedeachtime
WeatherDatahasnewmeasurements.
Thesystemmustbeexpandableotherdeveloperscancreate
newcustomdisplayelementsanduserscanaddorremoveas
manydisplayelementsastheywanttotheapplication.
AFirstMisguidedAttemptatthe
WeatherStation
public class WeatherData {
// instance variable declarations
public void measurementsChanged ( ) {
float temp = getTemperature ( );
float humidity = getHumidity ( );
float pressure = getPressure ( );
Whatswrongwiththefirst
implementation?
public class WeatherData {
// instance variable declarations
public void measurementsChanged ( ) {
float temp = getTemperature ( );
float humidity = getHumidity ( );
float pressure = getPressure ( );
TimefortheObserver!
TheNewspaperorMagazinesubscriptionmodel:
Anewspaperpublishergoesintobusinessandbegins
publishingnewspapers
Yousubscribetoaparticularnewspaper,andeverytimethere
isanewedition,itsgetsdeliveredtoyou.Aslongasyou
remainasubscriber,yougetnewnewspapers.
Youunsubscribewhenyoudontwantthenewspapers
anymoreandtheystopbeingdelivered
Whilethepublisherremainsinbusinesspeople,hotels,airlines
etcconstantlysubscribeandunsubscribetothenewspaper.
Publishers+Subscribers=ObserverPattern
The observers have subscribed to the
Subject to receive updates when the
subjects data changes.
Publisher==Subject
Subscribers==Observers
Subject object
manages some data.
2
2
int
This object isnt an
observer so it doesnt get
notified when the
subjects data changes.
Observer Objects
TheObserverPatternDefined
TheObserverPatterndefinesaonetomanydependencybetween
objectssothatwhenoneobjectchangesstate,allofitsdependentsare
notifiedandupdatedautomatically.
One to many relationship (Subject can have many observers)
Object that holds state
int
Automatic update/notification
Observer Objects
Dependent objects
(observers are
dependent on the
subject to update
them when data
changes.)
ObserverClassDiagram
Heres the Subject interface. Objects use
this interface to register as observers and
also to remove themselves from being
observers.
DesigningtheWeatherStation
Subject interface
<<interface>>
Subject
<<interface>>
Observer
observers
registerObservers ( )
removeObservers ( )
notifyObservers ( )
<<interface>>
DisplayElement
update ( )
WeatherData
registerObservers ( )
removeObservers ( )
notifyObservers ( )
CurrentConditions
ForecastDisplay
update ( )
display ( ) { // display
current measurements }
update ( )
display ( ) { // display
the forecast }
StatisticsDisplay
getTemperature ( )
getHumidity ( )
getPressure ( )
measurementsChanged ( )
display ( )
WeatherData now
implements the Subject
interface.
update ( )
display ( ) { // display
avg, min, and max
measurements }
ImplementingtheWeatherStation
public interface Subject {
Both of these methods take an Observer
public void registerObserver (Observer o);
as an argument, that is the Observer to
be registered or removed.
public void removeObserver (Observer o);
public void notifyObservers ( );
This method is called to notify all
}
ImplementingtheSubjectInterface
inWeatherData
public class WeatherData implements Subject {
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData ( ){
observers = new ArrayList ( );
}
public void registerObserver (Observer o) {
observers.add(o);
}
public void removeObserver (Observer o) {
int j = observer.indexOf(o);
if (j >= 0) {
observers.remove(j);
}}
public void notifyObservers ( ) {
for (int j = 0; j < observers.size(); j++) {
Observer observer = (Observer)observers.get(j);
observer.update(temperature, humidity, pressure);
}}
public void measurementsChanged ( ) {
notifyObservers ( ); }
// add a set method for testing + other methods.
TheDisplayElements
Implements the Observer and DisplayElement interfaces
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperatue;
The constructors passed the
private float humidity;
weatherData object (the subject)
private Subject weatherData;
and we use it to register the display
as an observer.
public CurrentConditionsDisplay (Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver (this);
}
public void update (float temperature, float humidity, float pressure) {
this.temperature = temperature;
When update ( ) is called, we
this.humidity = humidity;
save the temp and humidity and
call display ( )
display ( );
}
public void display ( ){
System.out.println( Current conditions : + temperature + F degrees and + humidity + %
humidity );
}
}
The display ( ) method just prints out the most recent temp and humidity.
UsingJavasBuiltinObserver
Pattern
JavahasbuiltinsupportinseveralofitsAPIsfortheObserverpattern
Mostgeneral:ObserverinterfaceandtheObservableclassinthejava.util
package.
Observer == Observer
Observable == Subject
Observable
Observable is
a CLASS not
an interface,
so
WeatherData
extends it!
addObserver ( )
deleteObserver ( )
notifyObservers ( )
setChanged ( )
WeatherData
getTemperature ( )
getHumidity ( )
getPressure ( )
This doesnt
look familiar -we will see it
shortly.
WeatherData
does not need
to implement
register,
remove and
notify -- it
inherits them
<<interface>>
Observer
update ( )
GeneralDisplay
update ( )
display ( )
ForecastDisplay
update ( )
display ( )
StatisticsDisplay
update ( )
display ( )
UsingJavasBuiltinObserver
Pattern
ForanObjecttobecomeanObserver:
ImplementtheObserverinterface(thistimethejava.util.Observer
interface)andcalladdObserver()onanyObservableobject.To
removeusedeleteObserver()method.
FortheObservabletosendnotifications
BecomeanObservablebyextendingjava.util.Observablesuperclass
Thena2stepprocess:
1.
2.
FirstcallthesetChanged()methodtosignifythatthestatehaschangedin
yourobject.
ThencalloneoftwonotifyObservers()methods
This takes an arbitrary data
FortheObservertoreceivenotifications
Implementtheupdate()methodasbefore.Signatureabitdifferent.
update (Observable o, Object arg)
ThesetChanged()Method
ThesetChanged()methodisusedtosignifythatthestatehaschangedandthat
notifyObservers(),whenitiscalled,shouldupdateitsobservers.
IfnotifyObservers()iscalledwithoutfirstcallingthesetChanged(),theobserverswillNOT
benotified.
Pseudocode:
setChanged ( ){
changed = true;
}
notifyObservers ( Object arg ){
if (changed ) {
for every observer on the list {
call update(this, arg);
}
changed = false;
}
}
notifyObservers ( ) {
notifyObservers (null);
}
And after it notifies the observers it sets the changed flag back to false.
WhyisthesetChanged()
necessary?
setChanged()methodistheretogiveyoumore
flexibility
Optimizethenotifications
Example:
ifthesensorsaresensitivereadingsmayfluctuatebyafewtenthsofthe
adegree.
Maynotwanttoupdatetheobserverswitheveryfluctuation
setChanged()allowsyoutocontrolthenotificationpoints.
OtherrelevantmethodsinObservable:
clearChanged()
hasChanged()
Thenotify()PushandPull
Methods
public void measurementsChanged ( ) {
setChanged ( );
notifyObservers ( );
}
TheDarkSideofthe
java.util.Observable
Doesntthejava.util.ObservableviolateOOdesignprincipleof
programmingtointerfacesandnotimplementations?
Yes it does! Observable is a class and not an interface. Moreover it does
not even implement an interface.
java.util.Observable has a number of problems that limit its usefulness
and reuse
1) Observable is a class: you have to subclass it => you cant add on the
Observable behavior to an existing class that already extends
another superclass. This limits its potential reuse.
2) There isnt an Observable interface so you cannot provide your own
implementation or swap out the Observable implementation with say
a multithreaded implementation
3) Observable protects crucial methods: setChanged () is protected. It
means that you cannot call setChanged unless you have subclassed
Observable. Violates : favor composition over inheritance!
OtherplacestofindObserver
PatterninJava
BothJavaBeansandSwingalsoprovideimplementationsof
theObserverpattern
LookunderthehoodofJButtonssuperclass
AbstractButton
Hasmanyadd/removelistenermethods:allowyoutoaddand
removeobservers(calledlistenersinSwing)
Theselistenersareavailableforvarioustypesofeventsthatoccur
ontheSwingcomponent
Example:ActionListenerletsyoulisteninonanytypesof
actionsthatmightoccuronabuttonlikeabuttonpress.
AlsocheckoutthePropertyChangeListenerinJavaBeans
ASimpleExample:ALife
ChangingApplication
Background:
simpleapplicationwithonebuttonthatsaysShouldI
doit.
Whenyouclickonthebuttonthelistenersgetto
answerthequestioninanywaytheywant.
Codesample:implements2suchlisteners:
AngelListenerandDevilListener
TheLifeChangingCode
public class SwingObserverExample {
JFrame frame;
public static void main (String[] args){
SwingObserverExample example = new SwingObserverExample ( );
example.go ( );
}
public void go ( ){
frame = new JFrame ( );
JButton button = new JButton (Should I do it);
button.addActionListener (new AngelListener ( ) );
button.addActionListener (new DevilListener ( ));
frame.getContentPane().add(BorderLayout.CENTER, button);
// set frame properties here
}
class AngelListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
System.out.println(Dont do it, you might regret it!);
}
}
class DevilListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
System.out.println(Come on, do it!);
}
}
Summary
OOPrincipleinplay:Striveforlooselycoupleddesignsbetweenobjectsthat
interact.
Mainpoints:
TheObserverpatterndefinesaonetomanyrelationshipbetweenobjects
Subjects(observables),updateObserversusingacommoninterface
ObserversarelooselycoupledinthattheObservableknowsnothingaboutthem,other
thantheyimplementtheObserverinterface.
YoucanpushorpulldatafromtheObservablewhenusingthepattern(pullis
consideredmorecorrect)
DontdependonaspecificorderofnotificationforyourObservers
JavahasseveralimplementationsoftheObserverPatternincludingthegeneralpurpose
java.util.Observable
Watchoutforissueswithjava.util.Observable
DontbeafraidtocreateourownversionoftheObservableifneeded
SwingmakesheavyuseoftheObserverpattern,asdomanyGUIframeworks
YoufindthispatterninotherplacesaswellincludingJavaBeansandRMI.