name: information expert problem: solution: discussion · activity, having some patterns help the...

42
GRASP GRASP stands for General Responsibility Assignment Solution Patterns. There are nine pattern in the Layman text: Information Expert (Expert) Creator High Cohesion Low Coupling Controller Polymorphism Pure Fabrication Indirection Protected Variations Information Expert Name: Information Expert Problem: What is the general principle of assigning responsibilities to a class? Once the classes present in a problem description have been identified, how do we determine which class handles a responsibility. Solution: Assign a responsibility to the information expert, the class that has the information necessary to fulfill the responsibility. Discussion: Consider, Course WorkIte * * Student 1 1 which class should determine the final mark the student receives in a course. While the WorkItem class can determine the value of an individual items, they can not determine the final mark. The Student class should be assigned this responsibility since it knows about all of the work items. The Student class will rely on the WorkItem class to determine the individual marks. The Expert pattern has a real world analogy, who do you ask about X, you ask the expert who knows about X. Information Expert Examples In the Resistor design example, some of the responsibilities are: Who is responsible for maintaining the collection of resistors, and for accessing selected ranges of the resistor? Who is responsible for calculating the voltage divisor ratio? The Information expert design pattern can be used to assign the above responsibilities. Since the ResistorManager stores the list of resistors (i.e., it knows about the resistors), it should be responsible for selecting a range of resistors. The voltage divider ration must be calculated by the VoltageDivider since this class knows about the two resistors that form the voltage divider. More Information Expert Examples Consider the following responsibilities from paint estimator program: grasp file:///home/joans/Documents/Docencia/ES2/Curs... 1 of 22 09/12/2012 11:23 AM

Upload: others

Post on 07-Oct-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

GRASP

GRASP stands for General Responsibility Assignment Solution Patterns. There are nine pattern in the Layman text:

Information Expert (Expert)CreatorHigh CohesionLow CouplingControllerPolymorphismPure FabricationIndirectionProtected Variations

Information Expert

Name: Information Expert

Problem:

What is the general principle of assigning responsibilities to a class? Once the classes present in a problem descriptionhave been identified, how do we determine which class handles a responsibility.

Solution:

Assign a responsibility to the information expert, the class that has the information necessary to fulfill theresponsibility.

Discussion:

Consider,

Course WorkItem* *

Student

1 1

which class should determine the final mark the student receives in a course. While the WorkItem class can determinethe value of an individual items, they can not determine the final mark. The Student class should be assigned thisresponsibility since it knows about all of the work items. The Student class will rely on the WorkItem class to determinethe individual marks.

The Expert pattern has a real world analogy, who do you ask about X, you ask the expert who knows about X.

Information Expert Examples

In the Resistor design example, some of the responsibilities are:

Who is responsible for maintaining the collection of resistors, and for accessing selected ranges of the resistor?Who is responsible for calculating the voltage divisor ratio?

The Information expert design pattern can be used to assign the above responsibilities.

Since the ResistorManager stores the list of resistors (i.e., it knows about the resistors), it should be responsible forselecting a range of resistors.

The voltage divider ration must be calculated by the VoltageDivider since this class knows about the two resistors thatform the voltage divider.

More Information Expert Examples

Consider the following responsibilities from paint estimator program:

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

1 of 22 09/12/2012 11:23 AM

Page 2: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Who should calculate the amount of paint need to cover a given area?Who should be responsible calculating the amount of paint need for a wall?

Since the Paint class knows about the coverage, it should be responsible for calculating the required paint for a givenarea.

A wall knows about its paint, its area, and the list of doors and windows that a part of the wall, thus it has all theinformation necessary to calculate the amount of paint required.

Marking System Example

The marking system can be modeled with the following domain classes: WorkItem, MarkingScheme, Student, andCourse.

Consider the following responsibilities:

the calculation of the final grade for a student,editing a working item,the report of all the grades in a class,a list of all the student name and numbers in the class,

Using the Expert design pattern, decide which class if possible of the domain class should be assigned the givenresponsibility.

If no domain class is possible, suggest a software class that should be responsible.

Creator

Name: Creator

Problem:

Which class should be responsible for creating a new instance of some class. Since creating objects is a commonactivity, having some patterns help the quality of the design.

Solution:

Assign class B the responsibility of creating and instance of class A if:

B aggregates A objects,B contains A objects,B closely uses A objects,B has data needed to create an A object.

Discussion:

The last point is also an application of the Information Expert Design pattern, since an Expert knows about theinformation needed to create objects of class A.

Low Coupling

Name: Low Coupling

Problem:

“How to support low dependency, low change impact, and increase reuse?”

Solution:

Assign a responsibility so that coupling remains low.

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

2 of 22 09/12/2012 11:23 AM

Page 3: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Discussion:

A class with strong coupling relies on many other classes. This can result in:

changes in the class propagate to changes elsewhere,a class that is hard to understand in isolation,a class that is hard to reuse.

Low coupling in Java

The low coupling pattern is an evaluation principle. It is applied so that all design decisions can be evaluated.

In Java, common forms of coupling from type X to type Y include:

Type X contains an attribute of type Y,Type X has a method that references a type Y object,Type X is a direct or indirect subclass of type Y,Type Y is an interface that type X implements.

Low coupling

Low coupling supports classes that are more independent, which reduces the impact of change. Subclasses should becreated very carefully since the subclass is highly coupled to the super class.

Extreme low coupling should be avoided since it can result in in-cohesive and bloated classes.

The low coupling pattern should not be used as an excuse to avoid common utility classes that are found in java.util.*.When a class is stable (i.e., not likely to change) then the harm of coupling is greatly reduced. The real problem ofcoupling is not the linkage, but the fact that changes to couple classes affect each other.

Low coupling Exercise

Consider the method addTrack for an Album class, two possible methods are:

addTrack( Track t )

and

addTrack( int no, String title, double duration )

Which method reduces coupling?

The second one does, since the class using the Album class does not have to know a Track class.

In general, parameters to methods should use base types (int, char ...) and classes from the java.* packages.

Coupling between Wall and PaintAmountReporter

Consider the reportPaint method.

public void reportPaint( PaintAmountReporter reporter ) { reporter.addPaint( paint.getColour(), paintAmount() ); for( int i = 0 ; i < openings.size(); i++ ) { Opening o = openings.get( i ); reporter.addPaint( o.getTrimPaint().getColour(), o.trimArea()); }}

Is the coupling between PaintAmountReporter and Wall good or bad? How could it be removed?

High Cohesion

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

3 of 22 09/12/2012 11:23 AM

Page 4: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Name: High Cohesion

Problem:

“How to keep objects focused, understandable, and manageable?”

Solution:

Assign responsibilities so that cohesion remains high.

Discussion:

Cohesion measures the degree that the responsibilities in a class are related and if they are focused on the same goals.A software component with highly functionally related responsibilities is cohesive. This class does not attempt to do toomuch. A class with low cohesion does many unrelated things, or does too much work.

A class with low cohesion suffers from the following problems:

hard to comprehend,hard to reuse,hard to maintain,not robust.

Class with low cohesion often represent a very “large grain” of abstraction. They have taken on too manyresponsibilities.

Cohesion Examples

Examples illustrating varying degrees of functional cohesion are:

very low cohesion - A class is solely responsible for many things in very different functional areas. If mostprograms are implemented in one class, then that class would have very low cohesion.low cohesion - A class has sole responsibility for a complex task in one functional area.high cohesion - A class has moderate responsibilities in one functional area and collaborates with other classes tofulfill the task.

High Cohesion

Classes with high cohesion generally have a relatively small number of methods. The methods are related functionally.

A real world analogy of low cohesion is a person that takes on too many unrelated responsibilities, especially ones thatshould properly be delegated to others.

In any design decision both coupling and cohesion should be considered.

Coupling and Cohesion Exercise

Identify coupling and cohesion issues with the following code.

import java.util.ArrayList;import java.util.Iterator;

public class NumbersStatsCommand {

public static void main( String[] args ) { NumberSequence seq = new NumberSequence();

int i; for( i = 0 ; i < args.length; i++ ) { try { seq.appendNumber( Double.parseDouble( args[i] ) ); }

examples/NumbersStatsCommand.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

4 of 22 09/12/2012 11:23 AM

Page 5: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

catch( NumberFormatException ex ) { break; } } for(; i < args.length; i++ ) { System.out.println( args[i] + " " + seq.calculate( args[i] ) ); } }}

class NumberSequence { private ArrayList<Double> list;

public NumberSequence() { this.list = new ArrayList<Double>(); }

public void appendNumber( double d ) { list.add( new Double( d ) ); }

public double calculate( String cmd ) { if ( cmd.equals("sum") ) { double sum = 0.0; Iterator<Double> dit = list.iterator(); while ( dit.hasNext() ) { sum += dit.next().doubleValue(); } return sum; } else if ( cmd.equals("min") ) { Iterator<Double> dit = list.iterator(); double min = dit.next().doubleValue(); while ( dit.hasNext() ) { double d = dit.next().doubleValue(); if ( d < min ) { min = d; } } return min; } return 0.0; }}

Any bad practices?

Coupling and Cohesion Improvements

import java.util.ArrayList;import java.util.Iterator;

public class NumbersStatsCommandV2 {

public static void main( String[] args ) { NumberSequence seq = new NumberSequence();

int i; for( i = 0 ; i < args.length; i++ ) { try { seq.appendNumber( Double.parseDouble( args[i] ) ); } catch( NumberFormatException ex ) { break; } } for(; i < args.length; i++ ) { if ( args[i].equals("sum") ) {

examples/NumbersStatsCommandV2.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

5 of 22 09/12/2012 11:23 AM

Page 6: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

System.out.println( "sum: " + seq.sum() ); } else if ( args[i].equals("min") ) { System.out.println( "min: " + seq.min() ); } else { System.out.println( "unknown command: " + args[i] ); } } }}

class NumberSequence { private ArrayList<Double> list;

public NumberSequence() { this.list = new ArrayList<Double>(); }

public void appendNumber( double d ) { list.add( new Double( d ) ); }

public double sum() { double s = 0.0; Iterator<Double> dit = list.iterator(); while ( dit.hasNext() ) { s += dit.next().doubleValue(); } return s; }

public double min() { Iterator<Double> dit = list.iterator(); double m = dit.next().doubleValue(); while ( dit.hasNext() ) { double d = dit.next().doubleValue(); if ( d < m ) { m = d; } } return m; }}

Bad coupling and cohesion can result from assigning too many responsibilities to the same class or from assigning thesame responsibility to more than one class. In NumbersStatsCommand, the responsibility to parsing the command line hasbeen assigned to two classes.

Implementation Improvements

public class NumbersStatsCommandV3 {

public static void main( String[] args ) { NumberSequence seq = new NumberSequence();

int i; for( i = 0 ; i < args.length; i++ ) { try { seq.appendNumber( Double.parseDouble( args[i] ) ); } catch( NumberFormatException ex ) { break; } } if ( i == 0 ) { System.out.println( "no numbers" ); System.exit( 1 );

examples/NumbersStatsCommandV3.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

6 of 22 09/12/2012 11:23 AM

Page 7: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

} for(; i < args.length; i++ ) { if ( args[i].equals("sum") ) { System.out.println( "sum: " + seq.sum() ); } else if ( args[i].equals("min") ) { System.out.println( "min: " + seq.min() ); } else { System.out.println( "unknown command: " + args[i] ); } } }}

class NumberSequence { private double currentSum; private double currentMin;

public NumberSequence() { this.currentSum = 0.0; // Double.MAX_VALUE is the maximum double value // what is the benefit of this assignment? this.currentMin = Double.MAX_VALUE; }

public void appendNumber( double d ) { currentSum += d; if ( d < currentMin ) { currentMin = d; } }

public double sum() { return currentSum; }

public double min() { return currentMin; }}

Reduced coupling, enables a simpler and more efficient implementation, The client classes are not affected by thischange.

Another cohesion and coupling exercise

Identify the low cohesion and high coupling in the following program.

import java.util.regex.Pattern;import java.util.regex.Matcher;import java.util.Scanner;

public class GenerateReport { private static final Pattern pat = Pattern.compile( "<(-?\\d+),(-?\\d+)>" );

private double maxX = Double.MIN_VALUE; private double maxY = Double.MIN_VALUE; private double minX = Double.MAX_VALUE; private double minY = Double.MAX_VALUE;

public void processData() { Scanner sc = new Scanner(System.in); while( sc.hasNextLine() ) { String line = sc.nextLine(); Matcher matcher = pat.matcher( line ); double x, y;

cc/GenerateReport.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

7 of 22 09/12/2012 11:23 AM

Page 8: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

try { if ( matcher.matches() ) { x = Double.parseDouble( matcher.group(1)); y = Double.parseDouble( matcher.group(2)); if ( x < minX ) minX = x; if ( y < minY ) minY = y; if ( x > maxX ) maxX = x; if ( y > maxY ) maxY = y; } } catch( NumberFormatException ex ) { continue; // discard bad line } } }

public void genReport() { double largestMax = Math.max( maxX, maxY); double smallestMin = Math.min( minX, minY); double dist = Math.hypot(maxX-minX,maxY-minY);

System.out.println("Largest maximum is " + largestMax ); System.out.println("Smallest minimum is " + smallestMin ); System.out.println("Largest distance is " + dist ); }

public static void main( String[] args ) { GenerateReport rep = new GenerateReport(); rep.processData(); rep.genReport(); }}

Improved version

The class CoordinateData is only responsible for the coordinate information and any calculations on this information. Itdoes not deal with handling input or producing the report.

public class CoordinateData { private double maxX = Double.MIN_VALUE; private double maxY = Double.MIN_VALUE; private double minX = Double.MAX_VALUE; private double minY = Double.MAX_VALUE;

public void updateCoordinateData( double x, double y ) { if ( x < minX ) minX = x; if ( y < minY ) minY = y; if ( x > maxX ) maxX = x; if ( y > maxY ) maxY = y; }

public double getLargestMax() { return Math.max( maxX, maxY); }

public double getSmallestMin() { return Math.min( minX, minY); }

public double getLargestDist() { return Math.hypot(maxX-minX,maxY-minY); }

// Anything missing from this class?}

Classes with high cohesion generally have a relatively small number of methods. The methods are related functionally.

cc/CoordinateData.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

8 of 22 09/12/2012 11:23 AM

Page 9: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

These conditions are true for the CoordinateData class.

Parsing the coordinate data

The responsibility of parsing the data is now handled by the ParseCoordinateStream class. It does not handle anycalculation.

import java.io.InputStream;import java.util.Scanner;import java.util.regex.Pattern;import java.util.regex.Matcher;

class ParseCoordinateStream { private static final Pattern pat = Pattern.compile( "<(-?\\d+),(-?\\d+)>" );

private InputStream inStream; private Scanner scanner; private double x, y;

public ParseCoordinateStream( InputStream inStream ) { this.inStream = inStream; this.scanner = new Scanner( inStream ); }

public boolean fetchNextPair() { while ( scanner.hasNextLine() ) { String line = scanner.nextLine(); Matcher matcher = pat.matcher( line ); try { if ( matcher.matches() ) { x = Double.parseDouble( matcher.group(1)); y = Double.parseDouble( matcher.group(2)); return true; } } catch( NumberFormatException ex ) { continue; // discard bad line } } return false; }

public double getX() { return x; }

public double getY() { return y; }

public static void main(String args[] ) { ParseCoordinateStream parser = new ParseCoordinateStream(System.in); CoordinateData cd = new CoordinateData();

while ( parser.fetchNextPair() ) { cd.updateCoordinateData( parser.getX(), parser.getY() ); } System.out.println("Largest maximum is " + cd.getLargestMax() ); System.out.println("Smallest minimum is " + cd.getSmallestMin() ); System.out.println("Largest distance is " + cd.getLargestDist() ); }}

Again this class has a small number of functionally related methods, thus is cohesion is high.

Push model

cc/ParseCoordinateStream.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

9 of 22 09/12/2012 11:23 AM

Page 10: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Further reduction in coupling can occur with an implementation of a class the supports the push model of dataprocessing. In the push model the data is feed to the consuming class.

import java.io.InputStream;

class PushCoordinates {

private ParseCoordinateStream pullCoords;

public PushCoordinates( InputStream inStream ) { this.pullCoords = new ParseCoordinateStream( inStream ); }

public interface Push { public void push( double x, double y ); }

public void pushCoordinates( Push p ) { while ( pullCoords.fetchNextPair() ) { p.push( pullCoords.getX(), pullCoords.getY() ); } }

public static void main(String args[] ) { PushCoordinates pusher = new PushCoordinates(System.in); final CoordinateData cd = new CoordinateData();

pusher.pushCoordinates( new PushCoordinates.Push() { public void push( double x, double y ) { cd.updateCoordinateData(x, y); } }); System.out.println("Largest maximum is " + cd.getLargestMax() ); System.out.println("Smallest minimum is " + cd.getSmallestMin() ); System.out.println("Largest distance is " + cd.getLargestDist() ); }}

Any class that needs data, implements the Push interface. Coupling can be easily reduce, how?

Controller

Name: Controller

Problem:

“Which first object beyond the UI layer receives and coordinates a system operations?”

Solution:

Assign responsibility for receiving events to either: a class the represents the system, or a class the represents theparticular “use case”.

Discussion:

Controller classes provides the glue between the system events and software model. Since the type of use case tends tochange, the classes can change without affecting the rest of the system (i.e., coupling is reduced).

The UI classes only interact with the controller classes.

The controller classes normally delegates most of the work to other classes in the system.

cc/PushCoordinates.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

10 of 22 09/12/2012 11:23 AM

Page 11: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Entity, Boundary, and Control Objects

Entity objects are instances of domain classes.“Boundary objects represent the interaction between actors and the system”“Control objects are in charge of realizing use cases.”

Actors interact with boundary objects. Boundary object communicate and are controlled by control objects (Controllerdesign pattern). Control object interact with entity objects to accomplish the goals of the system.

Grouping objects into entity, boundary, and control classes provides a structure that aids and improves the softwaredesign of a system. Boundary objects can represent UI components, control objects are responsible for managing usecases, and entity objects represent the real world.

HiLo Game

In the HiLo game, a player has to guess a randomly selected number between a low and a high number. If their guessis too high or too low or correct they are informed, The goal of the game is to guess the correct number in a limitednumber of trys. The games should track the number of player wins and the total number of games played. The playershould also be given the opportunity to to choose the low and high numbers.

PlayGame Use Case

Use Case Name: PlayGame

Actor: HiLo Player

Precondition: A game has started with a selected range and a randomly chosen number to guess. The user has 10guesses.

Flow of events: Basic Path

A hilo game has started with a selected range and a randomly chosen number to be guess.1.While the user still has guesses available:

The user is prompted to enter a guess.1.If the user enters a number, then

if the guessed number is higher than the correct number, report that the guess is higher, and returnto step 2.1.

1.

if the guessed number is lower than the correct number, report that the guess is lower, and return tostep 2.1.

2.

if the guessed number matches the choose number, report the success and the use case ends.3.

2.

If the user quits, the use case ends.3.

2.

The use case ends.3.

Postcondition: A user has either won, lost or quit the game.

For this use case:

is the use case too complicated,is the use case too simple,does the post condition describe a real change,is the interaction too specific to an interface technology,are the any problems,is there anything missing, andcan the description be improved (i.e., made to read better).

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

11 of 22 09/12/2012 11:23 AM

Page 12: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

StartGame Use Case

Use Case Name: StartGame

Actor: HiLo Player

Precondition: At least one hilo game has occurred.

Flow of events: Basic Path

A user requests the statistics of the last set of games played.1.The system displays the number of wins and the number of games played.2.The use case ends.3.

Postcondition: None

For this use case:

is the use case too complicated,is the use case too simple,does the post condition describe a real change,is the interaction too specific to an interface technology,are the any problems,is there anything missing, andcan the description be improved (i.e., made to read better).

StartGame Use Case

Use Case Name: StartGame

Actor: HiLo Player

Precondition: None

Flow of events: Basic Path

The user is informed that a new games is starting and asked to select the low number and high number.1.While the user has not correctly entered the low and high numbers:

The user is prompted to enter the low number and high number.1.If the user enters valid numbers, the use case ends.2.If the user requests to quit, the game stops, and the use case ends.3.

2.

The use case ends.3.

Postcondition: The range of numbers to guess has been selected.

For this use case:

is the use case too complicated,is the use case too simple,does the post condition describe a real change,is the interaction too specific to an interface technology,are the any problems,is there anything missing, andcan the description be improved (i.e., made to read better).

HiLoGame (entity)

The state of a HiLo can be modeled by:

package hilo;

import java.util.Random;

public class HiLoGame {

private static Random random = new Random();

hilo/hilo/HiLoGame.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

12 of 22 09/12/2012 11:23 AM

Page 13: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

private int high, low; private int range; private int guess; private int guessCount; private int noGames; private int noWins;

public HiLoGame( int low, int high ) { this.low = low; this.high = high; this.range = (high-low) + 1; this.noGames = 0; this.noWins = 0; newGame(); }

public void newGame() { guessCount = 0; guess = random.nextInt( range ) + low; noGames++; }

/* * Return 0 if the guess is correct, > 0 if too high, * and < 0 if too low. */ public int makeGuess( int userGuess ) { if ( userGuess == guess ) { noWins++; return 0; } guessCount++; return userGuess - guess; }

public int numGuesses() { return guessCount; }

public int numWins() { return noWins; }

public int numGames() { return noGames; }}

Does this class do one thing, and is it done well?How many other classes does it depend on?

StartHiLoGame (control class)

This class implements the StartHiLoGame use case, and is an example of the Controller pattern.

package text;

import hilo.HiLoGame;

import java.util.Scanner;

public class StartHiLoGame {

private int defaultLo = 0; private int defaultHi = 100;

/*

hilo/text/StartHiLoGame.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

13 of 22 09/12/2012 11:23 AM

Page 14: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

* Return a HiLoGame or null to indicate end of game. */ public HiLoGame start() { Scanner scan = new Scanner( System.in ); System.out.println("Welcome to HiLo"); do { System.out.println("Please pick the guessing range [0 100] or quit"); String line = scan.nextLine(); Scanner sl = new Scanner( line ); int hi = defaultHi; int lo = defaultLo; if ( sl.hasNextInt() ) { lo = sl.nextInt(); if ( sl.hasNextInt() ) { hi = sl.nextInt(); System.out.println("Starting game with " + lo + " " + hi); return new HiLoGame( lo, hi ); } } else if ( sl.hasNext() ) { String cmd = sl.next(); if ( cmd.equals( "quit" ) ) { System.out.println("quitting"); return null; } } else { System.out.println("Starting game with " + lo + " " + hi); return new HiLoGame( lo, hi ); } } while( true ); }}

Does this class do one thing, and is it done well?How many other classes does it depend on?

PlayHiLoGame (control class)

This class implements the PlayHiLoGame use case, and is an example of the Controller pattern.

package text;

import hilo.HiLoGame;

import java.util.Scanner;

public class PlayHiLoGame { private HiLoGame game;

public PlayHiLoGame( HiLoGame game ) { this.game = game; }

public boolean play() { Scanner scan = new Scanner(System.in); while( game.numGuesses() <= 10 ) { System.out.print( "Enter a guess: "); String line = scan.nextLine(); Scanner sl = new Scanner( line ); if ( sl.hasNextInt() ) { int guess = sl.nextInt(); int result = game.makeGuess( guess ); if ( result == 0 ) { System.out.println("Correct guess, you win"); break; }

hilo/text/PlayHiLoGame.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

14 of 22 09/12/2012 11:23 AM

Page 15: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

else if ( result > 0 ) { System.out.println("too high"); } else { System.out.println("too low"); } int rem = 10 - game.numGuesses(); System.out.println(rem + " trys left"); } else if ( sl.hasNext() ) { String cmd = sl.next(); if ( cmd.equals("quit") ) { return false; } System.out.println("Invalid command, only quit accepted"); } else { System.out.println("empty line"); } } return true; }}

Does this class do one thing, and is it done well?How many other classes does it depend on?

ReportStatstHiLoGame (control class)

This class implements the ReportStatstHiLoGame use case, and is an example of the Controller pattern.

package text;

import hilo.HiLoGame;

public class ReportStatstHiLoGame { private HiLoGame game;

public ReportStatstHiLoGame( HiLoGame game ) { this.game = game; }

public void report() { int wins = game.numWins(); int games = game.numGames(); System.out.println( "won " + wins + " out of " + games ); }}

Does this class do one thing, and is it done well?How many other classes does it depend on?

HiLoGameSystem (control class)

This class implements the system and is an example of the Controller pattern.

package text;

import hilo.HiLoGame;

public class HiLoGameSystem { public static void main( String[] args ) { StartHiLoGame startGame = new StartHiLoGame(); while ( true ) { HiLoGame game = startGame.start();

hilo/text/ReportStatstHiLoGame.java

hilo/text/HiLoGameSystem.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

15 of 22 09/12/2012 11:23 AM

Page 16: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

if ( game == null ) break; PlayHiLoGame playGame = new PlayHiLoGame( game ); ReportStatstHiLoGame statsGame = new ReportStatstHiLoGame(game); while( playGame.play() ) { statsGame.report(); game.newGame(); } } }}

Does this class do one thing, and is it done well?How many other classes does it depend on?

HiLo Game Class Diagram

Comment on the coupling and cohesion of the HiLo game implementation.

Swing version of HiLo

A screen shot of the the HiLo game implemented with swing is:

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

16 of 22 09/12/2012 11:23 AM

Page 17: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

HiLoControl (control)

package gui;

import hilo.HiLoGame;

public class HiLoControl {

public HiLoControl( HiLoApp gui ) { this.gui = gui; this.game = new HiLoGame(0, 100); }

private HiLoApp gui; private HiLoGame game;

public void playGame( int guess ) { int result = game.makeGuess( guess ); if ( result == 0 ) { gui.displayPlayResult("You Win, New game"); int wins = game.numWins(); int games = game.numGames(); gui.appendScoreResults( "won " + wins + " out of " + games + "\n" ); game.newGame(); } else { int remaining = 10 - game.numGuesses(); if ( remaining <= 0 ) { gui.displayPlayResult("Too many trys, New game"); int wins = game.numWins(); int games = game.numGames(); gui.appendScoreResults( "won " + wins + " out of " + games + "\n" ); game.newGame(); } else { if ( result < 0 ) { gui.displayPlayResult("Too low, trys " + remaining + " left"); } else { gui.displayPlayResult("Too high, trys " + remaining + " left"); } } }

hilo/gui/HiLoControl.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

17 of 22 09/12/2012 11:23 AM

Page 18: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

}

public void setRange( int hi, int low ) { game = new HiLoGame( low, hi ); gui.displayPlayResult( "Guess a number between " + low + " " + hi ); }

public static void main( String args[] ) { final HiLoApp app = new HiLoApp(); HiLoControl control = new HiLoControl( app ); app.setControl( control );

java.awt.EventQueue.invokeLater(new Runnable() { public void run() { app.setVisible(true); } }); }}

Does this class do one thing, and is it done well?How many other classes does it depend on?

HiLoApp (boundary)

/* * To change this template, choose Tools | Templates * and open the template in the editor. */

/* * App.java * * Created on Oct 31, 2009, 6:50:26 PM */

package gui;

/** * * @author rod */public class HiLoApp extends javax.swing.JFrame {

private HiLoControl control;

public void setControl( HiLoControl control ) { this.control = control; }

public void displayPlayResult( String msg ) { playResultField.setText( msg ); }

public void appendScoreResults( String msg ) { scoreTextArea.append( msg ); }

/** Creates new form App */ public HiLoApp() { initComponents(); }

/** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor.

hilo/gui/HiLoApp.java

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

18 of 22 09/12/2012 11:23 AM

Page 19: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

*/ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() {

topPanel = new javax.swing.JPanel(); frameTitle = new javax.swing.JLabel(); playForm = new javax.swing.JPanel(); playInputForm = new javax.swing.JPanel(); guessLabel = new javax.swing.JLabel(); guessField = new javax.swing.JTextField(); guessButton = new javax.swing.JButton(); playResultField = new javax.swing.JLabel(); rangeForm = new javax.swing.JPanel(); rangeButton = new javax.swing.JButton(); highForm = new javax.swing.JPanel(); highLabel = new javax.swing.JLabel(); highField = new javax.swing.JTextField(); lowForm = new javax.swing.JPanel(); lowLabel = new javax.swing.JLabel(); lowField = new javax.swing.JTextField(); scoreForm = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); scoreTextArea = new javax.swing.JTextArea();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("HiLo"); // NOI18N setBackground(new java.awt.Color(48, 219, 231)); setBounds(new java.awt.Rectangle(0, 0, 100, 90)); setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); setName("top_frame"); // NOI18N getContentPane().setLayout(new java.awt.GridLayout(1, 1));

topPanel.setBackground(new java.awt.Color(173, 240, 203)); topPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5)); topPanel.setMaximumSize(new java.awt.Dimension(500, 600)); topPanel.setMinimumSize(new java.awt.Dimension(300, 400)); topPanel.setPreferredSize(new java.awt.Dimension(300, 400)); topPanel.setLayout(new javax.swing.BoxLayout(topPanel, javax.swing.BoxLayout.PAGE_AXIS));

frameTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); frameTitle.setLabelFor(this); frameTitle.setText("HiLo Game"); frameTitle.setAlignmentX(0.5F); frameTitle.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); frameTitle.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); topPanel.add(frameTitle);

playForm.setBorder(javax.swing.BorderFactory.createTitledBorder("Play")); playForm.setOpaque(false); playForm.setLayout(new javax.swing.BoxLayout(playForm, javax.swing.BoxLayout.PAGE_AXIS));

playInputForm.setOpaque(false);

guessLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); guessLabel.setLabelFor(guessField); guessLabel.setText("Guess"); guessLabel.setAlignmentY(0.0F); playInputForm.add(guessLabel);

guessField.setColumns(10); playInputForm.add(guessField);

guessButton.setText("Play"); guessButton.setMinimumSize(new java.awt.Dimension(70, 29)); guessButton.setPreferredSize(new java.awt.Dimension(100, 29)); guessButton.setRequestFocusEnabled(false); guessButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) {

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

19 of 22 09/12/2012 11:23 AM

Page 20: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

guessButtonActionPerformed(evt); } }); playInputForm.add(guessButton);

playForm.add(playInputForm);

playResultField.setText("Guess a number between 0 and 100"); playResultField.setAlignmentX(0.5F); playForm.add(playResultField);

topPanel.add(playForm);

rangeForm.setBackground(new java.awt.Color(227, 231, 38)); rangeForm.setBorder(javax.swing.BorderFactory.createTitledBorder("Range")); rangeForm.setOpaque(false); rangeForm.setLayout(new javax.swing.BoxLayout(rangeForm, javax.swing.BoxLayout.PAGE_AXIS));

rangeButton.setText("Set Guess Range"); rangeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rangeButtonActionPerformed(evt); } }); rangeForm.add(rangeButton);

highForm.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 1, 1, 1)); highForm.setOpaque(false);

highLabel.setText("High Guess"); highLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); highForm.add(highLabel);

highField.setColumns(10); highField.setHorizontalAlignment(javax.swing.JTextField.LEFT); highField.setText("100"); highForm.add(highField);

rangeForm.add(highForm);

lowForm.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); lowForm.setOpaque(false);

lowLabel.setText("Low Guess"); lowLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); lowForm.add(lowLabel);

lowField.setColumns(10); lowField.setText("0"); lowForm.add(lowField);

rangeForm.add(lowForm);

topPanel.add(rangeForm);

scoreForm.setBorder(javax.swing.BorderFactory.createTitledBorder("Scores")); scoreForm.setOpaque(false); scoreForm.setLayout(new java.awt.GridLayout(1, 1));

scoreTextArea.setColumns(20); scoreTextArea.setRows(10); jScrollPane1.setViewportView(scoreTextArea);

scoreForm.add(jScrollPane1);

topPanel.add(scoreForm);

getContentPane().add(topPanel);

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

20 of 22 09/12/2012 11:23 AM

Page 21: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

pack(); }// </editor-fold>//GEN-END:initComponents

private void guessButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_guessButtonActionPerformed if ( control == null ) return; String guess = guessField.getText(); try { int g = Integer.parseInt( guess ); control.playGame( g ); } catch( NumberFormatException ex ) { displayPlayResult("not a number, try again"); } }//GEN-LAST:event_guessButtonActionPerformed

private void rangeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rangeButtonActionPerformed if ( control == null ) return; try { String lowText = lowField.getText(); String highText = highField.getText(); int hi = Integer.parseInt( highText ); int lo = Integer.parseInt( lowText ); control.setRange( hi, lo ); } catch( NumberFormatException ex ) { displayPlayResult("invalid range"); } }//GEN-LAST:event_rangeButtonActionPerformed

/** * @param args the command line arguments */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new HiLoApp().setVisible(true); } }); }

// Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel frameTitle; private javax.swing.JButton guessButton; private javax.swing.JTextField guessField; private javax.swing.JLabel guessLabel; private javax.swing.JTextField highField; private javax.swing.JPanel highForm; private javax.swing.JLabel highLabel; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextField lowField; private javax.swing.JPanel lowForm; private javax.swing.JLabel lowLabel; private javax.swing.JPanel playForm; private javax.swing.JPanel playInputForm; private javax.swing.JLabel playResultField; private javax.swing.JButton rangeButton; private javax.swing.JPanel rangeForm; private javax.swing.JPanel scoreForm; private javax.swing.JTextArea scoreTextArea; private javax.swing.JPanel topPanel; // End of variables declaration//GEN-END:variables

}

Does this class do one thing, and is it done well?How many other classes does it depend on?

HiLo Game Class Diagram (gui)

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

21 of 22 09/12/2012 11:23 AM

Page 22: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

GUI and Text

Comment on the differences between the two implementations.

grasp file:///home/joans/Documents/Docencia/ES2/Curs...

22 of 22 09/12/2012 11:23 AM

Page 23: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Remaining GRASP

The remaining 4 GRASP patterns will be covered.

Polymorphism - behaviour depends on the typePure Fabrication - class based in software worldIndirection - avoid direct coupling with an intermediaryProtected Variations - information hiding - open/close

The first five GRASP patterns were:

Expert - assign responsibilities to class with knowledgeCreator - knows the necessary details to createHigh Cohesion - does related thingsLow Coupling - reduce connectivityController - use cases or system based classes

Polymorphism

Name: Polymorphism

Problem:

How to handle behaviour based on type (i.e., class), but not with an if or switch statement?Polymorphism is also used to create pluggable software components.

“ When alternate behaviors are selected based on the type of an object, use polymorphicmethod call to select the behavior, rather than use if statements to test the type. ”, Patterns inJava, Vol 2., p 69

Solution:

In Java, polymorphism is realized by overriding a method from a super class or implementingan interface. The implemented overridden methods are polymorphic in that a client class usesthe same method, but the behaviour depends on the type of the object being referenced.

Discussion:

The Polymorphism GRASP pattern deals with how a general responsibility gets distributed toa set of classes or interfaces. For example, the responsibility of calculating grades depends onthe type of marking scheme for a particular student.

If polymorphism is not used, and instead the code tests the type of the object, then thatsection of code will grow as more types are added to the system. This section of code becomesmore coupled (i.e., it knows about more types) and less cohesive (i.e., it is doing too much).

A software component is pluggable if it presents itself as the known class or interface.

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

1 of 20 09/12/2012 11:24 AM

Page 24: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Responsibilities that can be polymorphic

Consider the following.

How creatures respond to being attacked in a DandD game.How a connection is made to a WIFI access point.How a ship in the game of Battleship is displayed on screen.How much time a route takes to travel depends on the type of segments in the route.How a wall is detected by a robot depends on the type of sensors used.How a player plays a game a RISK depends of if the player is a human or machine.

In each of the above cases, the type of the object being asks results in different behaviour.The polymorphism pattern assigns the responsibility to a subclass or a class the implements aknown interface.

Anymore examples from the projects?

Polymorphism in Java API

Polymorphism is used throughout the Java API, consider:

The hashCode(), toString(), getClass(), equals(), and clone() methods of java.lang.Objectshould or must be provided by all Java class (since all Java classes inheritjava.lang.Object).The drawing and event processing of Swing components is the responsibilities of eachdistinct Swing component. The Swing package provides many more examples ofpolymorphism (e.g., javax.swing.plaf.UIResource, javax.swing.border.AbstractBorder,javax.swing.text.AbstractDocument, ... ).Similar to the Swing package, the AWT package also has examples of polymorphism.The data structures and algorithms used by the classes that implement java.util.Listdepend on the implementing class (e.g., array for ArrayList, linked list for LinkedList).The java.util.Bag, java.util.Set, and java.util.Map are interfaces for concrete classes thatimplement different data structures and algorithms for these interfaces.The java.io.Reader, java.io.Writer have extended class that specialize the basic IOoperations.Other Java examples of polymorphism are: java.util.EventObject,java.util.concurrent.ExecutorService, javax.imageio.IIOParam, java.sql.ResultSet,java.security.Key, ...

See http://falkhausen.org/ for class diagrams of the Java api.

Polymorphism in java.io

Identify the polymorphism is the code that copies files:

import java.io.IOException;import java.io.BufferedReader;import java.io.FileReader;import java.io.BufferedWriter;import java.io.FileWriter;

poly/CopyFile.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

2 of 20 09/12/2012 11:24 AM

Page 25: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

public class CopyFile { public static void main( String[] args ) throws IOException { if( args.length != 2 ) { System.out.println("usage: java CopyFile infile outfile"); System.exit( 1 ); } BufferedReader rd = new BufferedReader( new FileReader( args[0] )); BufferedWriter wt = new BufferedWriter( new FileWriter( args[1] )); String line = null; while( (line=rd.readLine()) != null ) { wt.write( line ); wt.newLine(); } rd.close(); wt.close(); }}

Polymorphism with streams

The polymorphism is more explicit in this example:

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.FileInputStream;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileOutputStream;

public class CopyFileStream { public static void main( String[] args ) throws IOException { if( args.length != 2 ) { System.out.println("usage: java CopyFileStream infile outfile"); System.exit( 1 ); } InputStream ins = new BufferedInputStream( new FileInputStream( args[0] )); OutputStream os = new BufferedOutputStream( new FileOutputStream( args[1] )); byte[] buf = new byte[2048]; int amt; while( (amt=ins.read( buf )) > 0 ) { os.write( buf, 0, amt ); } ins.close(); os.close(); }}

Polymorphism example (interface)

poly/CopyFileStream.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

3 of 20 09/12/2012 11:24 AM

Page 26: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

A possible set of two dimensional shapes include: circle, triangle, and square. Each of theseshapes has an area and a perimeter. The calculation of area and perimeter depend on thetype of shape.

A possible shape interface is:

public interface Shape2D { public double area(); public double perimeter();}

Class implementations for circle, triangle, and square are:

import static java.lang.Math.PI;

public class Circle implements Shape2D { private double radius;

public Circle( double radius ) { this.radius = radius; }

public double area() { return PI * radius * radius; }

public double perimeter() { return PI * 2 * radius; }

}

import static java.lang.Math.sqrt;

public class Triangle implements Shape2D { private double a, b, c;

public Triangle( double a, double b, double c ) { this.a = a; this.b = b; this.c = c; }

public double area() { // Heron's formula return sqrt( (a+b-c)*(a-b+c)*(-a+b+c)*(a+b+c) ) / 4.0; }

public double perimeter() { return a+b+c; }

shapes/Shape2D.java

shapes/Circle.java

shapes/Triangle.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

4 of 20 09/12/2012 11:24 AM

Page 27: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

}

public class Square implements Shape2D { private double side;

public Square( double side ) { this.side = side; }

public double area() { return side * side; }

public double perimeter() { return 4 * side; }}

The Information Expert pattern suggests that the area and perimeter calculations belong toeach class, since the information need to calculate the area is present in each class.

Given a shape, code that print its area is:

Shape s = // a Triangle, Circle, or Square objectSystem.out.println( s.area() );

Without polymorphism, the code would be:

Shape s = // Triangle, Circle, or Squareif ( s instanceof Triangle ) { Triangle t = (Triangle)s; System.out.println( t.area() );else if ( s instanceof Circle ) { Circle c = (Triangle)c; System.out.println( c.area() );}else if ( s instanceof Square ) { Square sq = (Square)s; System.out.println( sq.area() );}

Of course without polymorphism, interfaces would not make any sense.

The second code fragment is not as cohesive as the first. It also has more coupling, since itknows about Triangle, Circle, and Square. Additionally, any new shapes require the modificationof the above code.

Polymorphism example (abstract class)

Inheriting from a class can also be used to realize the polymorphism of the perimeter and

shapes/Square.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

5 of 20 09/12/2012 11:24 AM

Page 28: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

area responsibilities. The class is abstract, since there are no meaningfully definition of areaand perimeter without a real shape.

import static java.lang.Math.sqrt;import static java.lang.Math.PI;

public abstract class AbstractShape { public abstract double area(); public abstract double perimeter();}

class Triangle extends AbstractShape { private double a, b, c;

public Triangle( double a, double b, double c ) { this.a = a; this.b = b; this.c = c; }

public double area() { // Heron's formula return sqrt( (a+b-c)*(a-b+c)*(-a+b+c)*(a+b+c) ) / 4.0; }

public double perimeter() { return a+b+c; }}

class Square extends AbstractShape { private double side;

public Square( double side ) { this.side = side; }

public double area() { return side * side; }

public double perimeter() { return 4 * side; }}

class Circle extends AbstractShape { private double radius;

public Circle( double radius ) { this.radius = radius; }

shapes/AbstractShape.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

6 of 20 09/12/2012 11:24 AM

Page 29: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

public double area() { return PI * radius * radius; }

public double perimeter() { return PI * 2 * radius; }}

Larman suggest that interfaces should be used “ ..., when you want to support polymorphismwithout being committed to a particular class hierarchy”. Interfaces are also required whenmore then one set of methods must be polymorphic (i.e., multiple inheritance is required).

Expression Polymorphism

The expression, 3.0 * 2.0 + 1.0, can represented by an abstract syntax tree.

3.0 2.0 1.0

+

*

Every element in the tree can be evaluated. A class that represents any expression is:

public abstract class Expr { public abstract double evaluate();}

The polymorphism pattern suggest that every distinct expression object should override theevaluate method.

Constant, plus, and times expression can be implemented with:

public class ConstantExpr extends Expr { private double value;

public double evaluate() { return value; }

public ConstantExpr( double value ) { this.value = value; }}

AST/Expr.java

AST/ConstantExpr.java

AST/PlusExpr.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

7 of 20 09/12/2012 11:24 AM

Page 30: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

public class PlusExpr extends Expr { private Expr left, right;

public double evaluate() { return left.evaluate() + right.evaluate(); }

public PlusExpr( Expr left, Expr right ) { this.left = left; this.right = right; }}

public class TimesExpr extends Expr { private Expr left, right;

public double evaluate() { return left.evaluate() * right.evaluate(); }

public TimesExpr( Expr left, Expr right ) { this.left = left; this.right = right; }}

How would a subtraction expression be supported?

Testing Expr

import org.junit.*;import static org.junit.Assert.*;

/* * javac -cp junit-4.7.jar:. ExprTesting.java * java -cp junit-4.7.jar:. org.junit.runner.JUnitCore ExprTesting */

public class ExprTesting { private static final Expr one = new ConstantExpr( 1.0 ); private static final Expr negOne = new ConstantExpr( -1.0 ); private static final Expr two = new ConstantExpr( 2.0 ); private static final double EPSILON = 1e-10;

@Test public void singleExpressions() { // expr: 1.0 assertTrue( one.evaluate() == 1.0 ); // expr: -1.0 assertTrue( negOne.evaluate() == -1.0 ); // expr: 2.0 assertTrue( two.evaluate() == 2.0 );

AST/TimesExpr.java

AST/ExprTesting.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

8 of 20 09/12/2012 11:24 AM

Page 31: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

}

@Test public void compoundExpressions() { // expr: 1.0 + 2.0 PlusExpr pe = new PlusExpr( one, two ); assertEquals( pe.evaluate(), 3.0, EPSILON ); // expr: 1.0 * 2.0 TimesExpr te = new TimesExpr( one, two ); assertEquals( te.evaluate(), 2.0, EPSILON ); // expr: -1.0 * (1.0 + 2.0) TimesExpr e1 = new TimesExpr( negOne, pe ); assertEquals( e1.evaluate(), -3.0, EPSILON ); // expr: (1.0 * 2.0) * (1.0 + 2.0) TimesExpr e2 = new TimesExpr( te, pe ); assertEquals( e2.evaluate(), 6.0, EPSILON ); }}

Nonpolymophic Expression Implementation

An implementation of a nonpolymophic expression evaluator is:

public class NonPolyExpr { public static final int CONST_EXPR = 1; public static final int PLUS_EXPR = 2; public static final int TIMES_EXPR = 3;

private int type; private double value; private NonPolyExpr left=null, right=null;

public NonPolyExpr( int type, double value ) { this.type = type; this.value = value; }

public NonPolyExpr( int type, NonPolyExpr left, NonPolyExpr right) { this.type = type; this.left = left; this.right = right; }

public double evaluate() { switch( type ) { case CONST_EXPR: return value; case PLUS_EXPR: return left.evaluate() + right.evaluate(); case TIMES_EXPR: return left.evaluate() * right.evaluate(); } return java.lang.Double.NaN; // what is this? }

AST/NonPolyExpr.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

9 of 20 09/12/2012 11:24 AM

Page 32: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

}

The nonpolymophic implementation suffers from the following design problems:

The NonPolyExpr.evaluate method is not as cohesive as the polymorphic versions, since theNonPolyExpr class must handle all the cases, while the polymorphic class only deal withone operation.The NonPolyExpr cannot be easily extended, while the polymorphic version is extended byadding new class the extends Expr. This new expression operation can then be used byall other classes.Using NonPolyExpr.evaluate, requires knowledge of the expression types, and therefore ismore coupled to the client classes.What is the result of:

// a, b are NonPolyExpr objectsNonPolyExpr e = new NonPolyExpr(NonPolyExpr.CONST_EXPR,a,b);System.out.print( e.evaluate() );

An implementation of polymorphism in C

The following C-language program demonstrates the essentials of how polymorphism isimplemented. In addition to the data parts of an object, the object contains a table of methodpointers for each overridden method. The table is consulted to invoke the correct method.

#include <stdio.h>

typedef void (*func_v_vp_ptr)(void *);

typedef struct { int value; // data part func_v_vp_ptr print; // virtual method} base_class;

void base_print(void *p){ base_class *self = (base_class *)p; printf("base %d\n", self->value );}

voidbase_init( base_class *self, int value){ self->value = value; self->print = base_print;}

voidinvoke_print( base_class *self ){ (*self->print)(self);}

c-poly/poly_in_c.c

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

10 of 20 09/12/2012 11:24 AM

Page 33: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

void derived_print(void *p){ base_class *self = (base_class *)p; printf("derived %d\n", self->value );}

voidderived_init( base_class *self, int value){ self->value = value; self->print = derived_print;}

intmain( int ac, char *av[] ){ base_class b1, d1;

base_init( &b1, 1); derived_init( &d1, 2);

invoke_print( &b1 ); invoke_print( &d1 );}

Hopeful, this demonstrates why learning C is good for you (or perhaps not!).

Pure Fabrication

Name: Pure Fabrication

Problem:

“ What object should have the responsibility, when you do not want to violate High Cohesionand Low Coupling, or other goals, but solutions offered by Expert are not appropriate. ”,Larman, p 421.

“ You must assign a responsibility to a class, but assigning it to a class that represents aconceptual model entity would ruin its low coupling or high cohesion. You resolve thisproblem by fabricating a class that does not represent an entity in your conceptual model. ”,Patterns in Java, Vol. 2, p 73.

In other words, not all responsibilities can be assigned to domain classes, especiallyresponsibilities that deal with implementation technologies (i.e., persistence storage, networkcommunication, ...).

Solution:

“ Assign a highly cohesive set of responsibilities to an artificial or convenience class that does

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

11 of 20 09/12/2012 11:24 AM

Page 34: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

not represent a problem domain concept -- something made up, to support high cohesion, lowcoupling, and reuse. ”, Larman, p 421.

Discussion:

Most of GoF patterns are pure fabrications (i.e., solely software constructs).

Pure Fabrication Examples

Some examples of pure fabrication, from earlier in the notes.

VoltageDividerSearcher - responsible for searching algorithmPaintEstimater - coordinates the estimationPaintAmountReporter - responsible totaling paint amountsReceiptPrinter - output of receiptsFormattedReceiptPrinter - output of receipts

What is common for all of the above pure fabrication classes?

Pure Fabrication Example

In the game of HiLo, a partial class that records the score of a game could be:

public Class ScoreRecord { private String playerName; private int numTries;

/* ... */}

To preserve the score results in between execution of the game, the game must save the scoreresults to permanent storage. The Information Expert pattern recommends that theScoreRecord class receive this responsibility since it has all the information. However, addingresponsibility to save the scores reduces the cohesion of the class, since storing informationpersistent is different then knowing about a score result.

Cohesive can be maintained by adding a pure fabrication class, PerserveScoreResult, which isresponsible for saving and retrieving the score results. This class has no corresponding objectin the problem domain.

Threaded Web Server

Some of the possible domain classes in a web server are: HttpRequest, Cookie, HttpResponse,MimeType, HttpRequestTask, ...

In this example, the HttpRequestTask class provides a thread to handle a HTTP request.Efficient web servers can support multiple HTTP requests by handling each request in aseparate thread. However to manage multiple threads, the system requires a pure fabricationclass to manage the threads. Add thread management to HttpRequestTask would decreasethe class's cohesion. The class provided by the Java api to manage threads is

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

12 of 20 09/12/2012 11:24 AM

Page 35: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

java.util.concurrent.ThreadPoolExecutor.

Indirection

Name: Indirection

Problem:

“ Where to assign a responsibility, to avoid direct coupling between two or more things? Howto de-couple objects so that low coupling is supported and reuse potential remains higher? ”,Larman, p 426.

Solution:

“ Assign the responsibility to an intermediate object to mediate between other components orservices so that they are not directly coupled. The intermediary creates an indirectionbetween the other components. ”, Larman, p 426.

Discussion:

The following GoF patterns are related: Adapter, Bridge, Facade, Observer, and Mediator.

Indirection aside

“'Most problems in computer science can be solved by another level of indirection' is an oldadage with particular relevance to object-oriented design. ”, quote at Larman, p 427.

Some examples of problems solved with an another level of indirections:

implementation of polymorphism - a pointer to an array of method points,pass by reference,linked lists,a multi-dimensional array where the rows/columns have different sizes,treating a head pointer the same as a pointer in a record,inheritance in prototype languages, like Javascript.

Entity, Boundary, and Control Objects (Review)

Entity objects are instances of domain classes.“Boundary objects represent the interaction between actors and the system”“Control objects are in charge of realizing use cases.”

Actors interact with boundary objects. Boundary object communicate and are controlled bycontrol objects (Controller design pattern). Control object interact with entity objects toaccomplish the goals of the system.

Grouping objects into entity, boundary, and control classes provides a structure that aids andimproves the software design of a system. Boundary objects can represent UI components,control objects are responsible for managing use cases, and entity objects represent the real

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

13 of 20 09/12/2012 11:24 AM

Page 36: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

world.

Indirection and Control Object

Most of the control objects are created by applying the Indirection pattern to de-couple theboundary objects from the entity objects.

The inner classes used to create event handlers are examples of control objects.

Indirection used to Glue Components

Intermediary objects are often used to glue fixed components (cannot be changed by you) tonewly created classes.

Arrays.binarySearch relies on classes that implement the Comparator interface to performthe searching.Arrays.sort relies on classes that implement the Comparator interface to perform thesorting.File.list relies on classes that implement the FileFilter to return a set of filtereddirectory entries.java.util.Timer relies on classes that implement the TimerTask to run the relevant code.

java.file.FileFilter Example

List the files with a standard image suffix.

import java.io.FileFilter;import java.io.File;

public class ImageFileFilter implements FileFilter {

private final String[] imageExtensions = new String[] {"jpg", "png", "gif"};

public boolean accept(File file) { for (String ext : imageExtensions) { if (file.getName().toLowerCase().endsWith(ext)) { return true; } } return false; }

public static void main( String[] args ) { File cwd = new File("."); // current working dir File[] files = cwd.listFiles(new ImageFileFilter()); for ( File f : files ) { System.out.println("file: " + f.getName()); } }}

indirect/ImageFileFilter.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

14 of 20 09/12/2012 11:24 AM

Page 37: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

java.util.Timer Example

The Exit class links the java.util.Timer with the application code.

import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;import java.util.Timer;import java.util.TimerTask;

public class TimerCountDown {

// inner static class private static class Exit extends TimerTask { private int count;

public Exit( int count ) { this.count = count; }

public void run() { System.out.println("count: " + count ); count--; if ( count <= 0 ) { System.out.println("too late, exiting"); System.exit( 0 ); } } }

/** * The initial thread starts with main. */ public static void main( String[] args ) throws IOException { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); Exit exit = new Exit( 10 ); Timer timer = new Timer("ticker" ); timer.schedule( exit, 1000, 1000 ); String line = null; while ( (line=in.readLine()) != null ){ if ( line.equals("stop") ) { exit.cancel(); System.out.println("timer cancelled"); break; } else { System.out.println("what?"); } } }}

indirect/TimerCountDown.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

15 of 20 09/12/2012 11:24 AM

Page 38: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

Protected Variations

Name: Protected Variations

Problem:

“ How to design objects, subsystems, and systems so that the variations or instability in theseelements does not have an undesirable impact on other elements. ”, Larman, p 427.

Solution:

“ Identify points of predicted variation or instability; assign responsibilities to create a stableinterface around them. ”, Larman, p 427.

Interface is used broadly in this context.

Discussion:

“ This is a very important, fundamental principle of software design! Almost every software orarchitectural design trick in this(sic) book - data encapsulation, polymorphism, date-drivedesign, interfaces, virtual machines, configuration files, operating systems, and much more -is specialization of Protected Variations. ”, Larman, p 428.

This design principle has been around for years, one initial formulation is due to David Parnasis called information hiding.

Mechanisms Motivated by Protected Variations(PV)

“ PV is a root principle motivating most of the mechanisms and patterns in programming anddesign to provide flexibility and protection from variations - variation in data, behaviour,software components, operating systems, and more. ”, Larman, p 428.

Some examples of system/architectures motivated by PV are:

operating systems hide and protect access to the machine resources. OS provide virtualCPUS, virtual memory, and virtual devices.everything is a file provided by the UNIX operating system hides how data is receivedand sent to the devices. UNIX treats, data stored in file systems, mass storage devices,network devices, audio devices, video devices, terminals, modems, ...,the Java Virtual Machine (JVM) in theory provides the ability to “write once, runeverywhere”. Once a JVM is written, the underlying OS is hidden from a Java program.overridden methods and interfaces allow the implementation to change and evolvewithout changes to the client classes.the protected and private visibility modifiers enforce access restriction to support PV.the println hides how lines are terminated by different operating systems (\n, \r, \n\r).

Don't Talk to Strangers (Law of Demeter)

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

16 of 20 09/12/2012 11:24 AM

Page 39: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

The Don't Talk to Strangers design pattern is a variation of PV. In this pattern, an objectwithin a method should only communicate with:

the self (this) object,an instance variable of this,a parameter of the methodan element of a collection that is referenced from a instance variable of this, andan object created in the method.

This pattern prevents the following:

void bar() { // long chain of communication foo.m1().m2().m3().m4();}

The method bar is coupled to all the objects in the chain. This is very brittle, since a changeany object along the change can cause problems.

Types of variation in PV

Variation in PV can be classified into:

variation point - variation that exist in the current system (e.g., different markingschemes).evolution point - variation that is based on speculation for future system change.

Information Hiding

From Parnas's On the Criteria To Be Used in Decomposing Systems Into Modules

“We propose instead that one begins with a list of difficult design decisions or designdecisions which are likely to change. Each module is then designed to hide such a decisionfrom others.”

Example of common design decisions to be hidden are:

boundary classes hide the user interface details (notice that the user interface is oneelement of a project that is mostly to change, or the best way for user interaction is hardto determine),control classes hide how the boundary classes interacts with the entity classes (anychange in the user interface will change how the interface is controlled),entity classes hide how the problem domain is modeled by the software component (theattributes and how those attributes are represented commonly change).the format of data input and output to a program is constantly changing and must behidden in their own modules,

Open-Closed principle by Meyer

The open-closed principle also equivalent to PV. A definition of OCP is:

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

17 of 20 09/12/2012 11:24 AM

Page 40: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

“Modules should be open (for extensions; adaptable) and closed (the module is closed tomodifications in ways the affect the clients).”, Larman, p 434.

Bertrand Meyer also developed the object-oriented programming language called Eiffel.Eiffel support “Design by Contract” where:

each routine (method) defines a precondition that must be true before the routine isexecuted,each routine defines a postcondition that must be true after the routine is executed, anda class invariant, which is true after construction, and before and after routine calls.

In Eiffel, these condition are checked at run time, and an exception is raise if the condition isnot true. These conditions can be used to construct test cases.

Assertion in Java

More details can be found at: http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html.

The assert statement in Java can be used to implement pre/post/class invariant conditions.The assert statement takes the form:

assert boolean_condition; // orassert boolean_condition : expr ;

A AssertionError is thrown if the condition evaluates as false. In the second from, the value ofexpr is passed to the appropriate AssertionError.

Normal the boolean condition and expr should be side effect free.

Assertions are enabled with the -ea. Assertions in a particular class are enabled with-ea:mypackage.myclass. The following command enables all assertions the the MyCal program:

java -ea MyCal

Assertion Example

An example of “Design by Contract” with the Java assert statement is:

/* * MyCal - implements a simple calendar. * * This code illustrates using assert to * implement pre/post/class invariant conditions. */

public class MyCal {

private int day; /* 1 <= day <= days in month */ private int month; /* 1 <= month <= 12 */

assert/MyCal.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

18 of 20 09/12/2012 11:24 AM

Page 41: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

private int year; /* 0 <= year */

/* check the class invariant */ private boolean checkClass() { return (1 <= month && month <= 12) && (1 <= day && day <= daysInMonth(month)) && (0 <= year); }

// no modification implies no checking public boolean leapYear() { return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0) ); }

private static final int[] monthDaysTable = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

private int daysInMonth( int m ) { assert 1 <= m && m <= 12; return monthDaysTable[ m - 1 ]; }

public MyCal( int year, int month, int day ) { this.year = year; this.month = month; this.day = day; assert checkClass(); // class invariant }

public void nextDay() { assert checkClass(); // class invariant

// notice that the invariant can be false // during the execution of a method day++; if ( day > daysInMonth( month ) ) { day = 1; month++; if ( month > 12 ) { month = 1; year++; } }

assert checkClass(); // class invariant }

public int getYear() { return year; }

/* .... */

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

19 of 20 09/12/2012 11:24 AM

Page 42: Name: Information Expert Problem: Solution: Discussion · activity, having some patterns help the quality of the design. Solution: Assign class B the responsibility of creating and

}

Assertion Example

Assertion for IntStack are:

import java.util.List;import java.util.LinkedList;

public class IntStack { private List<Integer> stack = new LinkedList<Integer>();

public IntStack() { assert size() == 0; // post condition }

public int size() { return stack.size(); }

public void push( int x ) { int currentSize = size(); // used of assert

Integer wrapper = new Integer( x ); stack.add( wrapper );

// post conditions assert x == stack.get(currentSize); assert currentSize+1 == size(); }

public int pop() throws StackException { int sz = size(); if ( sz <= 0 ) { throw new StackException("no element"); } sz--; // calculate last index Integer i = stack.remove( sz );

assert sz == size(); // post condition return i.intValue(); }}

class StackException extends Exception { public StackException( String msg ) { super( msg ); }}

A more elaborate design by contract system is described by http://en.wikipedia.org/wiki/Java_Modeling_Language.

assert/IntStack.java

grasp2 file:///home/joans/Documents/Docencia/ES2/Curs...

20 of 20 09/12/2012 11:24 AM