overview of eyewitness patterns –will need observer pattern. –in using observer pattern, we will...

42
Overview of Eyewitness Patterns Will need Observer pattern. In using Observer pattern, we will end up needing Adapter pattern. Let’s look at each in turn, starting with Adapter.

Post on 19-Dec-2015

223 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Overview of Eyewitness Patterns

– Will need Observer pattern.

– In using Observer pattern, we will end up needing Adapter pattern.

– Let’s look at each in turn, starting with Adapter.

Page 2: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

The Adapter Pattern

– Context: • You are building an inheritance hierarchy and want to

incorporate it into an existing class. • The reused class is also often already part of its own

inheritance hierarchy.

– Problem: • You do not have access to multiple inheritance or you do not

want to use it.

Page 3: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Adapter

– Solution:

«Adaptee»

adaptedMethod

«Superclass»

polymorphicMethod

«Adapter»

polymorphicMethod()

return adaptee.adaptedMethod();

{

}

Page 4: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Adapter

• Example:

TimsTorus

calcVolume

ThreeDShape

volume

Sphere Torus

volume()

return adaptee.calcVolume();

{

}

Page 5: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Adapter – Let’s code itinterface ThreeDShape {

public double volume();}

class Sphere implements ThreeDShape {

public double volume(){ ... }}

class TimTorus {

public double calcVolume(){ ... }}

class Torus implements ThreeDShape {

//an adapter class to tie into TimTorus

private TimTorus adaptee;

public Torus( TimTorus adaptee ){

this.adaptee = adaptee;}

public double volume(){ adaptee.calcVolume(); }}

TimsTorus

calcVolume

ThreeDShape

volume

Sphere Torus

Page 6: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Adapter

• Another Example:

Page 7: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Adapter

«Adaptee»

adaptedMethod

«Superclass»

polymorphicMethod

«Adapter»

polymorphicMethod()

return adaptee.adaptedMethod();

{ }

Page 8: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

6.6 The Observer Pattern

– Context: • When an association is created between two

classes, the code for the classes becomes inseparable.

• If you want to reuse one class, then you also have to reuse the other.

– Problem: • How do you reduce the interconnection between

classes, especially between classes that belong to different modules or subsystems?

• You want to maximize the flexibility of the system to the greatest extent possible

Page 9: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

ObserverSolution:

WeatherViewer

* ******

Observers are notified when a new prediction is readyForecaster

Observable

«ConcreteObservable» «ConcreteObserver»

«Observable»

addObservernotifyObservers

«interface»«Observer»

update

* ****** «interface»Observer

Page 10: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Observerable class

Page 11: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in
Page 12: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Let’s code it

WeatherViewer

* ******

Observers are notified when a new prediction is readyForecaster

Observable

«ConcreteObservable» «ConcreteObserver»

«Observable»

addObservernotifyObservers

«interface»«Observer»

update

* ****** «interface»Observer

Page 13: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

class Forecaster extends Observable {

public void newWeather( String prediction ){

setChanged(); //from super

notifyObservers( prediction ); //from super

}}

class WeatherViewer implements Observer {

public WeatherViewer( Observable forecaster ){

forecaster.addObserver( this );}

public void update( Observable obj, Object msg ){

String prediction = (String) msg;

SOP( prediction );}

}

Page 14: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

class Forecaster extends Observable {

public void newWeather( String prediction ){

setChanged(); //from super

notifyObservers( prediction ); //from super

}}

class Tornado implements Observer {

public Tornado( Observable forecaster ){

forecaster.addObserver( this );}

public void update( Observable obj, Object msg ){

String prediction = (String) msg;

if( isTornado( prediction ) ){ … }}

}

Page 15: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Project Eyewitness

ObservableServerObservableClient

AbstractServerAbstractClient

Observable

ConnectionToClient******

Page 16: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

No Can Do

ObservableServerObservableClient

AbstractServerAbstractClient

Observable

ConnectionToClient******

class ObservableClient extends AbstractClient, Observable {…}

Page 17: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Multiple-Inheritance Solution

ObservableServerObservableClient

AbstractServerAbstractClient

Observable

ConnectionToClient******

Page 18: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Can use Adapter to deal with multiple-inheritance

ObservableServerObservableClient

AbstractServerAbstractClient

Observable

ConnectionToClient

AdaptableServer

clientConnectedclientDisconnectedserverStartedserverStoppedhandleMessageFromClient

AdaptableClient

connectionEstablishedconnectionClosedhandleMessageFromServer

******

Page 19: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

The Observable layer of OCSF (continued)

ObservableServer

listenstopListeningclosesendToAllClientsisListeninggetClientConnectionsgetNumberOfClientsgetPortsetPortclientConnnectedclientDisconnectedserverStartedserverStoppedhandleMessageFromClient

ObservableClient

openConnectioncloseConnectionsendToServerisConnectedgetPortsetPortgetHostsetHostgetInetAddresshandleMessageFromServerconnectionClosedconnectionEstablished

ObservableAdaptableServerAdaptableClient

Page 20: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Using the observable layer1. Create a class that implements the Observer interface.2. Register it as an observer of the Observable:

Observable generator = … generator.addObserver(this); ...

 

3. Define the update method in the new class:  public void update(Observable obs, Object message) { if (message instanceOf SomeClass) { // process the message } } 

Page 21: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

End of section

 Once you do assignlet Patterns1, and understand previous slides, you are ready for the Eyewitness project.

But … before going on, consider another approach to the project. One that does not use Observable, but something different. You can do this as an alternative to using Observer on the project if you wish.

I’ll talk about this alternative in next set of slides.

Page 22: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Another look at Observer/Observable

• Let’s look at an alternative, one that is actually much more popular: event generator pattern.

• General idea: an event-generator class generates events (duh). Other classes are listeners – they sign up to hear certain events.

• So similar to Observer/Observable pattern. What is the difference?– Generate event objects. (See java.util.EventObject class.)

– Don’t extend Observable or implement Observer. (See HFDP page 71.)

– Build our own interfaces.

Page 23: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Let’s use an example: model of Telephone

public class Telephone { //note not using Observable

public void ringPhone() {

… //called when phone rings

}

public void answerPhone() {

… //called when phone answered

}

}

Page 24: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Ok, Now Look at Event-Generator pattern with Same Code

public class Telephone { //note not using Observable

public void ringPhone() {

… //called when phone rings

}

public void answerPhone() {

… //called when phone answered

}

}

Page 25: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Steps to using event generator• Step 1. Define event category classes

– Define a separate event category class for each major category of events that may be experienced and propagated by the event generator.

– Make each event-category class extend java.util.EventObject.

– Design each event-category class so that it encapsulates the information that needs to be propagated from the observable to the listeners for that category of events.

– Give the event-category class a name that ends in Event, such as TelephoneEvent.

Page 26: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

TelephoneEvent

Step 1. Define event category classes

public class TelephoneEvent

extends java.util.EventObject {

public TelephoneEvent(Telephone source) {

super(source);

}

}

Page 27: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in
Page 28: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

A few notes about TelephoneEvent

• Requiring an event source reference to be supplied every time an event object is created enables a single listener to register with multiple sources of the same event category. For example, a secret listening device object could register as a listener for multiple telephones. Upon being notified of a telephone event, it could then query the event object to find out which telephone generated the event.

• In addition, allowing the handler method to get a reference to the event source object enables the handler to ask the source for more information by invoking methods on the source. This is called the pull model in the observer-design-pattern literature, because the listener is pulling information out of the event generator after being notified of an event. It contrasts with the push model, in which all the information needed by the listener is encapsulated in the event object itself.

Page 29: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Step 2. Define listener interfaces

• For each event category, define a listener interface that extends java.util.EventListener and contains a method declaration for each event (of that category) that will trigger an information propagation from the event generator to its listeners.

• Name the listener interface by substituting Listener for Event in the event category class name. For example, the listener interface for TelephoneEvent would be TelephoneListener.

• Give the methods of the listener interface verb-based names describing in past tense the situation that triggered the event propagation. For example, a listener method for receiving a TelephoneEvent that was triggered by the phone ringing would be named telephoneRang().

• Each method should return void and take one parameter, a reference to an instance of the appropriate event category class. For example, the full signature of the telephoneRang() method would be:

void telephoneRang(TelephoneEvent e);

Page 30: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Interface TelephoneListenerpublic interface TelephoneListener extends java.util.EventListener {

void telephoneRang(TelephoneEvent e);

void telephoneAnswered(TelephoneEvent e);}

class MyTelephoneListener implements TelephoneListener{

void telephoneRang(TelephoneEvent e){}

void telephoneAnswered(TelephoneEvent e){}}

Page 31: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Step 3. Define the observable class

• For each category of events that will be propagated by instances of this class, define a pair of listener add/remove methods.

• Name the add method add<listener-interface-name>() and the remove method remove<listener-interface-name> (). For example, the listener add and remove methods for a TelephoneEvent would be named addTelephoneListener() and removeTelephoneListener().

• For each method of each event listener interface, define a private event propagator method that takes no parameters and returns void in the event generator's class that fires (propagates) the event.

• Name the event propagator method fire<listener-method-name>. For example, the name of the event propagator method for the event propagated via the telephoneRang() method of Telephone would be fireTelephoneRang().

• Update the code of the event generator's class so that it invokes the appropriate event propagator methods at the appropriate times.

Page 32: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Step 3a. signing up listeners• Name the add method add<listener-interface-name>() and the remove method

remove<listener-interface-name> (). For example, the listener add and remove methods for a TelephoneEvent would be named addTelephoneListener() and removeTelephoneListener().

public class Telephone {

private Vector telephoneListeners = new Vector();

public synchronized void addTelephoneListener(TelephoneListener l){

if (telephoneListeners.contains(l)) return;

telephoneListeners.addElement(l);}

public synchronized void removeTelephoneListener(TelephoneListener l) {

telephoneListeners.removeElement(l);}

Page 33: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Step 3b. Event propagator methods

• Name the event propagator method fire<listener-method-name>. For example, the name of the event propagator method for the event propagated via the telephoneRang() method of Telephone would be fireTelephoneRang().

public class Telephone {…private void fireTelephoneRang() {

Vector tl;synchronized (this) {

tl = (Vector) telephoneListeners.clone(); }

int size = tl.size();if (size == 0) return;

TelephoneEvent event = new TelephoneEvent(this);

for (int i = 0; i < size; ++i) { TelephoneListener listener = (TelephoneListener) tl.elementAt(i); listener.telephoneRang(event);} //for

} //fireTelephoneRang

private void fireTelephoneAnswered() { … }…

Page 34: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Step 3c. Change public methods

• Update the code of the event generator's class so that it invokes the appropriate event propagator methods at the

appropriate times.

public class Telephone {

public void ringPhone() {

fireTelephoneRang();

}

public void answerPhone() {

fireTelephoneAnswered();

}

Page 35: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Step 4. Define listener objects (example 1)

• To be a listener for a certain category of events, an object's class must simply implement the listener interface for that category of events.

public class AnsweringMachine implements TelephoneListener {

public void telephoneRang(TelephoneEvent e) { System.out.println("AM hears the phone ringing."); }

public void telephoneAnswered(TelephoneEvent e) { System.out.println("AM sees that the phone was answered."); }}

Page 36: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Step 4. Define listener objects (example 2)

• Use of an anonymous class as listener.

public class Person {

public void listenToPhone(Telephone t) {

t.addTelephoneListener( new MyTelephoneListener() { public void telephoneRang(TelephoneEvent e) { System.out.println("I'll get it!"); } } ); }}

Page 37: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Example of usepublic class Example1 {

public static void main(String[] args) {

Telephone ph = new Telephone(); Person bob = new Person(); AnsweringMachine am = new AnsweringMachine();

ph.addTelephoneListener(am); bob.listenToPhone(ph);

ph.ringPhone(); ph.answerPhone(); }}

When executed, the Example1 application prints out:

• The answering machine hears the phone ringing.• I'll get it!• The answering machine sees that the phone was answered.

Page 38: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Guidelines• Create just one event object for each "firing" and pass it to all listeners.

• Make the event object immutable, so there is no possibility that a listener will change the event object as it propagates.

• Use a single thread to notify all listeners. In other words, the fire method should go through the list of listeners and invoke the appropriate handler method upon one listener after the other.

• Take a snapshot (clone the list) of registered listeners at the beginning of the firing process, then send the event to each listener registered at the time the snapshot was taken.

• Keep event handlers (listener methods) short. These methods should execute quickly because (in the default approach) listeners are notified one at a time. In other words, listeners must wait until all listeners before them in the queue have been notified, so it is good citizenship for listeners to be quick about handling events. If an event handler method really needs to do considerable work as a result of an event notification, consider designing the handler such that it fires off or notifies another thread that does the actual time-consuming work.

• Don't write listeners such that they depend on an order of notification.

Page 39: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Guidelines (continued)If there are vast differences in the frequency of events in a particular event

category, consider defining separate listeners for high frequency and low frequency events. An example of this approach is illustrated by the MouseListener and MouseMotionListener interfaces of java.awt.event. Both of these listener interfaces define handler methods for MouseEvents. But because MouseEvents like "mouse moved" are generated so much more often than MouseEvents like "mouse pressed," the high frequency events like "mouse moved" get their own listener, MouseMotionListener. Lower frequency events like "mouse pressed" are handled by methods declared in plain old MouseListener.

Page 40: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Why is this better than Observable/Observer?

• Observable is a class you need to subclass to make an object observable. Thus, you have to find a way to fit Observable as a superclass in your observable class’ single-inheritance hierarchy. This is often difficult. (See Adapter example.)

• To turn a class into an observer, you need only implement a single interface, Observer. The single method declared in the Observer interface, update(Observable, Object), is used to notify the observers. The Observer interface and update() method are generic so they can be used in just about any situation.

Unfortunately, this generic design means that a programmer won't be able to easily understand code that uses Observer/Observable without digging into the nuts and bolts of the update handler methods. Contrast this with a listener that subclasses a MouseAdapter and overrides the mouseReleased() method. You already know a lot about the nature and source of the event just by looking at the names of the superclasses and methods, because they are more specific.

Page 41: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

One Interesting Note

• The observation patterns we have looked at each assumes that all classes in same JVM space.

• What if we are running in a distributed system?• For instance, we have a phone base station

and one or more cordless handsets.• Maybe there is a page() method on the base

station. Handsets listen for this event.• How do we transfer events wirelessly?• More generally, how can we use event

observation approach over the Internet?

Page 42: Overview of Eyewitness Patterns –Will need Observer pattern. –In using Observer pattern, we will end up needing Adapter pattern. –Let’s look at each in

Here is a little start for Eyewitness project

interface ClientListener extends java.util.EventListener {

void receivedMessageFromServer(ServerEvent e);

void receivedConnectionClosed(ConnectionEvent e);

void receivedConnectionException(ConnectionEvent e);

void receivedConnectionEstablished(ConnectionEvent e);}