Studying software design patterns is an effective way to learn from the experience of others

“Studying software design patterns is an effective way to learn from the experience of others” 1 Parties have different ways of presenting the resu...
Author: Dustin Barton
1 downloads 1 Views 406KB Size
“Studying software design patterns is an effective way to learn from the experience of others”

1

Parties have different ways of presenting the results.

Presentation of results

Coupling

Computation of results

“If the presentation classes and computation classes are coupled, then can’t reuse one without dragging along the other.”

For example, if you wanted to reuse bar chart code, you would need to take the computational class, since they are coupled.

Application runs algorithms on data, and produces the results: a, b, and c. How should the results be communicated to the interested parties?

2

Description  Context: – When associations are created between two classes, the code for the classes becomes inseparable (coupled): • Compiling one requires compiling the other. • Reusing one requires reusing the other. • Changing one likely requires changing the other.

Consequences of coupling.

 Issues: – How do you reduce the interconnection between classes, especially between classes that belong to different modules or subsystems? • Removing interconnection implies removing association. • When interconnection is removed, how can the classes communicate?

You want to minimize the coupling, but maintain usability. 3

The Observer Pattern The Problem – Balancing of Forces (Tradeoff)

DataSupplier

DataUser

In order to design the DataSupplier and DataUser for reusability – separately and independently – need to remove the association. But, how can you do this and still maintain usability?

4

Intermediate Solution (Anti-pattern) «Observable» addObserver notifyObservers

*

«ConcreteObservable»

«interface» * «Observer» update

Level 2 Level 1

«ConcreteObserver»

 The user application has two layers of software, Level 2 and Level 1.  The application adds observers by invoking addObserver in Level 2 for each observer in Level 1 that is interested in the data of the observerable in Level 1.  Whenever a Level 1 observable’s data has changed, the observable invokes notifyObservers in Level 2. The Level 2 method notifyObservers invokes the update method of each observer that is registered to receive data updates from the observable. 5

Intermediate Solution (Anti-pattern) «Observable» addObserver notifyObservers

*

«ConcreteObservable»

«interface» * «Observer» update

Level 2 Level 1

«ConcreteObserver»

• The components ConcreteObservable and ConcreteObserver may be reused independently, since there is no direct association between them: • In one application, many different Level 1 implementations may exist, and only one level 2 is required. For example, the following apps require sharing the Level 2 code: – An app in which a WeatherForecaster has many different kinds of WeatherViewers – An app in which Mouse events have many different watchers. – An app in which Keyboard events have many different watchers. • However, reusing a component requires the software in which it is reused has Level 2. The problem is that this requires sharing the Level 2 implementation, which would be okay if applied in the same application, but is problematic when applied across different applications/platforms. 6

The Best Solution «Observable» addObserver notifyObservers

*

«ConcreteObservable»

«interface» * «Observer» update

Compiler Layer Application Layer

«ConcreteObserver»

 Level 2 is implemented by the compiler: – For example, Java provides Observable and Observer classes: • i.e., Java implements the Observer Pattern.

– This is a better solution than the previous anti-pattern, but note that it requires the reusable components use the Java compiler. • This is reasonable, if the components and different applications are written in Java. 7

Example: Observable Keyboard «Observable» addObserver notifyObservers setChanged

Keyboard

* «interface» «Observer»

*

update

MyApp

Java Compiler Layer myApp Layer

KBHandler update

«interface» Runnable

• MyApp registers KBHandler as an observer of the observable Keyboard. • The observable Keyboard has a thread that continuously waits for and receives input from the Standard In (user input). • When it receives user input, the thread calls setChanged and notifyObservers. • Java’s implementation of the Observable invokes the update method of the KBHandler and passes it the string received from the Observable. • The update method the KBHandler processes the string in an application specific way. 8

import java.util.Observable; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Keyboard extends Observable implements Runnable { public void run() { try { final InputStreamReader isr=new InputStreamReader(System.in); final BufferedReader br = new BufferedReader(isr); while (true) { String response = br.readLine(); setChanged(); notifyObservers(response); } } catch (IOException e) { e.printStackTrace(); } } 9 }

import java.util.Observable; import java.util.Observer; /* this is Event Handler */ public class KBHandler implements Observer { private String userInput; public void update(Observable obj, Object arg) { if (arg instanceof String) { userInput = (String) arg; //Do something with the string; } } }

10

myApp CLASS (main METHOD) public class MyApp { public static void main(String[] args) { // create an observable – thread reads from stdin final Keyboard myKBEventSource = new Keyboard(); // create an observer final KBHandler myKBHandler= new KBHandler(); // Register the observer to the observable myKBEventSource.addObserver(myKBHandler); // starts the event thread Thread thread = new Thread(myKBEventSource); thread.start(); } } 11

• Keyboard class can be reused independently • To reuse Keyboard, the KBHandler class is not required, since Keyboard has no association to KBHandler. • In fact, Keyboard does not even know that KBHandler exists! • Needs the Observer pattern in Java.

• KBHandler class can be reused independently • To reuse the KBHandler, the Keyboard class is not required, since KBHandler has no association to Keyboard. • In fact, KBHandler does not even know that Keyboard exists! • Needs the Observer pattern in Java.

• MyApp class cannot be reused independently, since it has associations to Keyboard and KBHandler. • However, MyApp shows how to implement Observables and Observers using Java’s Observer Design Pattern.

12

Apply Observer Design Pattern to P2.3 Refactored Client

«Observable» addObserver notifyObservers

*

«ConcreteObservable»

«interface» * «Observer» update

Compiler Layer Application Layer

«ConcreteObserver»

13

>

Server

>

ClientTest

UserCommandHandler myUI myClient handleUserCommand

Client Client connectToServer disconnectFromServer sendMessageToServer isConnected stopThread setPort getPort sendMessageToUI run

StandardIO myCommmandHandler setCommand getUserInput display run

UserInterface update(String)

ServerMessageHandler handleServerMessage()

14

Steps 1. Identify the potential observables and observers in your application. 2. Redraw the UML class diagram to incorporate the observables and observers. For the observers, implement the update method. 3. Perform a reusability analysis.

15

Suggest Documents