CS 696: Advanced OO
| Observer | slide # 1 |
| ...Java Example | slide # 1 |
| ......The Classes | slide # 2 |
| ......Class Descriptions | slide # 3 |
| ......class Counter | slide # 5 |
| ......class IncreaseDetector | slide # 6 |
| ......abstract class CounterButton | slide # 7 |
| ......class IncreaseButton | slide # 8 |
| ......class DecreaseButton | slide # 8 |
| ......class CounterView | slide # 9 |
| ......class CounterTextView | slide # 10 |
| ......class ButtonController | slide # 11 |
| ......class RectangleView | slide # 12 |
| ......Sample Program | slide # 14 |
| ......Runtime Object Interaction | slide # 15 |
| ...Implementation Issues | slide # 16 |
| ......Mapping subjects(Observables) to observers | slide # 16 |
| ......Observing more than one subject | slide # 16 |
| ......Who Triggers the update? | slide # 17 |
| ......Make sure Subject is self consistent before Notification | slide # 18 |
| ......Adding information about the change | slide # 20 |
Use the Observer pattern:
Java's observer interface is the Observer abstract class in the pattern
Java's Observable class is the Subject abstract class in the pattern






/**
* A counter can increase or decrease by one. Each time a counter
* changes value, it notifies its observers of the type of change.
*/
class Counter extends Observable
{
public static final String INCREASE = "increase";
public static final String DECREASE = "decrease";
private int count = 0;
private String label;
public Counter( String label ) { this.label = label; }
public String label() { return label; }
public int value() { return count; }
public String toString() { return String.valueOf( count );}
public void increase()
{
count++;
setChanged();
notifyObservers( INCREASE );
}
public void decrease()
{
count--;
setChanged();
notifyObservers( DECREASE );
}
}/**
* IncreaseDetector is an observer that observes counters.
* IncreaseDetector counts the number of times one of its observables
* increases.
*/
class IncreaseDetector extends Counter implements Observer
{
public IncreaseDetector( String label )
{
super( label );
}
public void update( Observable whatChanged, Object message)
{
if ( message.equals( Counter.INCREASE) )
increase();
}
}
/**
* An abstract class for changing a counter each time the button is
* pressed
*/
abstract class CounterButton extends Button
{
protected Counter count;
public CounterButton( String buttonName, Counter count )
{
super( buttonName );
this.count = count;
}
public boolean action( Event processNow, Object argument )
{
changeCounter();
return true;
}
abstract protected void changeCounter();
}
/**
* A button that increases a counter each time the button is pressed
*/
class IncreaseButton extends CounterButton
{
public IncreaseButton( Counter count )
{
super( "Increase", count );
}
protected void changeCounter()
{
count.increase();
}
}
/**
* A button that decreases a counter each time the button is pressed
*/
class DecreaseButton extends CounterButton
{
public DecreaseButton( Counter count )
{
super( "Decrease", count );
}
protected void changeCounter()
{
count.decrease();
}
}/**
* A parent window view that observes a counter
*/
class CounterView extends Frame implements Observer
{
public CounterView( String label, int x, int y, int width, int
height )
{
setTitle( label );
reshape(x, y, width, height );
setLayout( new FlowLayout() );
}
/**
* Redraw the window when an observed counter changes
*/
public void update(Observable counter, Object argument)
{
repaint();
}
}/**
* A window for displaying the value of a counter in ascii
*/
class CounterTextView extends CounterView
{
Counter model;
public CounterTextView( Counter model, String label,
int x, int y, int width, int height )
{
super( label, x, y, width, height );
this.model = model;
model.addObserver( this );
show();
}
public void paint( Graphics display )
{
int y = bounds().height - 20;
int x = 20;
display.drawString( "The value of " + model.label() +
" is " + model , x, y );
}
/**
* A window for changing the value of a counter
*/
class ButtonController extends CounterView
{
public ButtonController( Counter model, int x, int y,
int width, int height )
{
super( model.label(), x, y, width, height );
model.addObserver( this );
// show the value of the counter
new CounterTextView( model, "Value of " + model.label(),
x + width + 5,y, 150, 50);
// buttons to change counter
add( new IncreaseButton( model ));
add( new DecreaseButton( model ));
show();
}
}
/**
* Draws a colored rectangle that depends on two counters. One
* counter is the width of the rectangle, the other counter is the
* height of the rectangle. The color of rectangle varies with its shape
*/
class RectangleView extends CounterView
{
Counter width;
Counter height;
public RectangleView( Counter rectWidth, Counter rectHeight,
int x, int y )
{
super( "Rectangle", x, y, 150, 150 );
height = rectHeight;
width = rectWidth;
rectWidth.addObserver( this );
rectHeight.addObserver( this );
show();
}
public void paint( Graphics display )
{
int x = 10;
int y = 10;
// Magnify value by 5 to get a bigger visual effect
int height = 5 * this.height.value();
int width = 5 * this.width.value();
// Determine color. Colors chosen for fun.
// The factor of 3 is just to magnify effect of change
if (( width >= 0 ) && ( height >= 0 ))
display.setColor( new Color( 3*width, 3*height,
width + height) );
else if (( width < 0 ) && ( height >= 0 ))
display.setColor( Color.pink );
else if (( width >= 0 ) && ( height < 0 ))
display.setColor( Color.orange );
else if (( width < 0 ) && ( height < 0 ))
display.setColor( Color.red );
display.fillRect(x, y, Math.abs(width), Math.abs( height ) );
}
}
class TestButton
{
public static void main( String args[] ){
Counter x = new Counter( "x" );
Counter y = new Counter( "y" );
IncreaseDetector plus = new IncreaseDetector( "Pluses" );
x.addObserver( plus );
y.addObserver( plus );
new ButtonControler( x, 30, 30, 150, 50 );
new ButtonControler( y, 30, 100, 150, 50 );
new CounterTextView( plus, "# of increases", 30, 170, 150, 50);
new RectangleView( x, y, 340, 30 );
}
}

Pass information in the update method
class Counter extends Observable
It might be inefficient or cause too many screen updates
class Counter extends Observable
{
Counter pageHits = new Counter();
pageHits.increase();
pageHits.increase();
pageHits.increase();
pageHits.notifyObservers(); }
class ComplexObservable extends Observable
{
Widget frontPart = new Widget();
Gadget internalPart = new Gadget();
public void trickyChange()
{
frontPart.widgetChange();
internalpart.anotherChange();
setChanged();
notifyObservers( );
}
}
class MyBetterClass extends ComplexObservable
{
Gear backEnd = new Gear();
public void trickyChange()
{
super.trickyChange();
backEnd.yetAnotherChange();
setChanged();
notifyObservers( );
}
}
class ComplexObservable extends Observable
{
Widget frontPart = new Widget();
Gadget internalPart = new Gadget();
/**
* Trigger update to observers
*/
public void trickyChange()
{
doThisChangeWithFactoryMethod();
setChanged();
notifyObservers( );
}
private void doThisChangeWithFactoryMethod()
{
frontPart.widgetChange();
internalpart.anotherChange();
}
}
class MyBetterClass extends ComplexObservable
{
Gear backEnd = new Gear();
private void doThisChangeWithFactoryMethod()
{
backEnd.yetAnotherChange();
}
}
class IncreaseDetector extends Counter implements Observer
{ // stuff not shown
public void update( Observable whatChanged, Object
message)
{
if ( message.equals( INCREASE) )
increase();
}
}
class Counter extends Observable
{ // some code removed
public void increase()
{
count++;
setChanged();
notifyObservers( INCREASE );
}
}
class IncreaseDetector extends Counter implements Observer
{ // stuff not shown
public void update( Observable whatChanged )
{
if ( whatChanged.didYouIncrease() )
increase();
}
}