to do: create a new class which adds statistics to the dice

25
2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.1 TO DO: Create a new class which adds statistics to the dice This class should add functionality to store the roll frequencies. You should implement a validation test (as well as running unit tests ) as below: E: Don’t forget to run regression tests

Upload: kailey

Post on 21-Jan-2016

18 views

Category:

Documents


0 download

DESCRIPTION

TO DO: Create a new class which adds statistics to the dice This class should add functionality to store the roll frequencies . You should implement a validation test ( as well as running unit tests ) as below :. NOTE: Don’t forget to run regression tests. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.1

TO DO: Create a new class which adds statistics to the dice

This class should add functionality to store the roll frequencies. You should implement a validation test (as well as running unit tests) as below:

NOTE: Don’t forget to run regression tests

Page 2: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.2

TO DO: Implement 2 different designs

//using inheritancepublic class DiceWithStatistics1 extends Dice implements DiceWithStatisticsSpecification{//…}

//using compositionpublic class DiceWithStatistics2 implements DiceWithStatisticsSpecification{//…protected Dice dice;//…}

If you have not developed your own solution code then you should try to understand my sample solution, which can be downloaded from the module web site: Dice-WithStatistics.zip

Page 3: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.3

Specification using an interface

package abstractions;

public interface DiceWithStatisticsSpecification extends DiceSpecification{

public abstract int frequencyOfRoll(int side) throws IllegalArgumentException;

public abstract boolean invariant();

public abstract void roll();

public String toString();

}

Note: Javadoc comments – not on the transparency, but included in the code – are used to update the documentation for the statistics specification

Page 4: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.4

TO DO: Implementation using inheritance

/** * * This class extends the behaviour of the {@link Dice} with * statistics for frequency of rolls<br> * These statistics are viewable through an updated toString method * * @author J Paul Gibson * @version 1 <br> * <ul> * <li> Design decision - use inheritance to extend already existing Dice behaviour </li> * <li> Implementation decision - store the roll frequencies in an array of integers </li> * </ul> */public class DiceWithStatistics1 extends Dice implements DiceWithStatisticsSpecification {

/** * Stores the number of times each side of the dice has been rolled */protected int rollsFrequency [];

Page 5: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.5

TO DO: Implementation using inheritance

/** * Create a default dice and reset the roll frequencies for each side to be 0<br> * Increment the count for the <code> numberOfDieWithStatistics</code> */

public DiceWithStatistics1 (){super();rollsFrequency = new int [NUMBEROFSIDES];resetFrequencies();numberOfDieWithStatistics++;}/** * Create a dice and reset the roll frequencies for each side to be 0<br> * Increment the count for the <code> numberOfDieWithStatistics</code> * @param sides can specify the number of sides * (within range of {@link DiceSpecification#MINIMUM_numberOfSides} .. * {@link DiceSpecification#MAXIMIM_numberOfSides}) */public DiceWithStatistics1 (int sides){super(sides);rollsFrequency = new int [NUMBEROFSIDES];resetFrequencies();numberOfDieWithStatistics++;}

Page 6: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.6

TO DO: Implementation using inheritance

public boolean invariant(){

if (rollsFrequency==null ) return false; if (rollsFrequency.length < NUMBEROFSIDES) return false; for (int i =0; i<NUMBEROFSIDES; i++) if (rollsFrequency[i] <0) return false;

return super.invariant();}

QUESTION: Could/Should this invariant be implemented in an abstract class?

Page 7: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.7

TO DO: Implementation using inheritance

/** * rolls the dice, updates the lastRoll value and updates the frequency history */public void roll(){

super.roll();rollsFrequency[lastRoll()-1] = rollsFrequency[lastRoll()-1]+1;

}

/** * @return the number of times the dice has rolled the specified side * @param side specifies the side of the dice for which we wish to know * the number of rolls */public int frequencyOfRoll(int side) throws IllegalArgumentException{if (side <=0 || side > MAXIMIM_numberOfSides)throw (new IllegalArgumentException("The number of sides specified is not valid")); return rollsFrequency[side-1];}

Page 8: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.8

TO DO: Implementation using inheritance

/** * @return a string representation of the current dice state, * including statistics */public String toString(){String str = super.toString();str = str+"\n Frequencies:\n";for (int i =0; i<dice.numberOfSides(); i++) str=str+"("+(i+1)+", "+rollsFrequency[i]+")";str=str+"\n";return str;}

QUESTION: Could/Should this method be implemented in an abstract class?

Page 9: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.9

TO DO: Implementation using composition

/** * * This class extends the behaviour of the {@link Dice} with statistics for * frequency of rolls<br> * These statistics are readable through the toString method * * @author J Paul Gibson * @version 1 <br> * <ul> * <li> Design decision - use composition to re-use already existing Dice behaviour </li> * <li> Implementation decision - store the roll frequencies in an array of integers </li> * </ul> */public class DiceWithStatistics2 implements DiceSpecification{

protected Dice dice;

/** * The number of dieWithStatistics objects that are currently instantiated<br> * We decrement this value when a DiceWithStatistics1 destructor is called - */protected static int numberOfDieWithStatistics = 0;

/** * Stores the number of times each side of the dice has been rolled */protected int rollsFrequency [];

Page 10: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.10

TO DO: Implementation using composition/** * Create a new DiceWithStatistics2 and reset the roll frequencies for each side to be 0<br> * The number of sides is set by default to {@link DiceSpecification#DEFAULT_numberOfSides}<br> * Increment the count for the <code> numberOfDieWithStatistics</code> */

public DiceWithStatistics2 (){dice = new Dice();rollsFrequency = new int [dice.numberOfSides()];resetFrequencies();numberOfDieWithStatistics++;}

/** * Create a new DiceWithStatistics2 and reset the roll frequencies for each side to be 0<br> * Increment the count for the <code> numberOfDieWithStatistics</code> * @param sides can specify the number of sides * (within range of {@link DiceSpecification#MINIMUM_numberOfSides} .. * {@link DiceSpecification#MAXIMIM_numberOfSides}) * <br> If it is not in range use the default number of sides ({@link DiceSpecification#DEFAULT_numberOfSides}) */

public DiceWithStatistics2 (int sides){dice = new Dice(sides);rollsFrequency = new int [dice.numberOfSides()];resetFrequencies();numberOfDieWithStatistics++;}

Page 11: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.11

TO DO: Implementation using composition

public int lastRoll (){ return dice.lastRoll();}

public int numberOfSides(){ return dice.numberOfSides();}

public int numberOfRolls(){ return dice.numberOfRolls();}

/** * Decrement the count for the number of current DiceWithStatistics that are instantiated */protected void finalize() throws Throwable{numberOfDieWithStatistics--;}

Page 12: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.12

TO DO: Implementation using composition

public boolean invariant(){

if (rollsFrequency==null ) dice.invariant(); else for (int i =0; i<dice.numberOfSides(); i++) if (rollsFrequency[i] <0) return false;

return true;}

public void roll(){dice.roll();rollsFrequency[lastRoll()-1] = rollsFrequency[lastRoll()-1]+1;}

public int frequencyOfRoll(int side) throws IllegalArgumentException{if (side <=0 || side > numberOfSides())throw (new IllegalArgumentException("The number of sides specified is not valid")); return rollsFrequency[side-1];}

Page 13: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.13

TO DO: Implementation using composition

/** * @return a string representation of the current dice state, including statistics */

public String toString(){String str = dice.toString();str = str+"\n Frequencies: \n";for (int i =0; i<dice.numberOfSides(); i++) str=str+"("+(i+1)+", "+rollsFrequency[i]+")";str=str+"\n";return str;}

Note: this is very similar to the toString method in the inheritance based design

/** * @return a string representation of the current dice state, * including statistics */public String toString(){String str = super.toString();str = str+"\n Frequencies: \n";for (int i =0; i<dice.numberOfSides(); i++) str=str+"("+(i+1)+", "+rollsFrequency[i]+")";str=str+"\n";return str;}

QUESTION: how to factor out the cut-and-paste code?

Page 14: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.14

TO DO: Write tests for both designs

• Unit tests• Validation tests

• Maximise re-use• Maximise re-usability• Minimize cut-and-paste programming

Page 15: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.15

TO DO: Create 2 different terminal/console views

The frequencies can either be displayed vertically or horizontally.(OPTIONAL: If the frequency values are bigger than the height/width of the screen then you should scale them in order to occupy as much of the screen as possible. The screen size should be stored in constant variables HEIGHT and WIDTH.)

1 |********2 |******3 |***4 |****5 |******6 |**7 |***8 |**9 |*****10 |11 |*****12 |**13 |********14 |*****15 |*********10.0 1.0

10.0 * * * * * * * * * * * * * * * * * * * * ** * * * ** * * * ** * * * *** ** ** * * *** ** ** * * *** ***** * * * *** ***** * * * *** ********* ***** ********* ***** ********* ***** ********* ***** ********* *****1.0 --------------- 123456789111111 012345

DISCUSSION:

How to best include these views in the design?

Page 16: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.16

The consequences of the initial design decision–

Choosing to implement a DiceWithStatistics as a subclass of Dice is a design decision that may have consequencies on later stages of the development.

The alternative re-use mechanism was to design a DiceWithStatistics class/object to have a Dice component class/object. This also may have consequencies on later stages of the development

DISCUSSION: What are the possible consequences (positive and negative)?

CLUE: You may have seen them when we considered the different views

OBSERVERS: We may wish to create different views that automatically update when the state of the models changes

Page 17: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.17

The Observer Design Pattern

This pattern is among the most useful for object-oriented software design.

It is a key part of the MVC pattern - the JDK itself makes heavyuse of a variant of this pattern in the 1.1 AWT eventdelegation model, and the Swing libraries also facilitate its use

The JDK libraries also provide a reusable implementation of the pattern in the form of the java.util.Observer interface and the java.util.Observable class.

Page 18: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.18

The Observer Design Pattern: UML

The idea of the pattern is to model a one-to-manydependency without tightly coupling the observed object withits many observers. When the observed object changes insome interesting way it can automatically notify all of itsobservers without knowing them directly

Page 19: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.19

Weaknesses

Unfortunately, a number of weaknesses have been identifiedin the JDK's Observer/Observable classes.

These weaknesses significantly limit the reusability and power of the classes, which is a shame since powerful reusability is a big part of what object oriented design is all about.

Most of the weaknesses are due to the fact that java.util.Observable is a class rather than an interface; orrather, that it is a class without a corresponding interface. Thisimplies that the only way to reuse Observable is to subclassit. You can't take an existing class and tack on the role ofObservable by having it implement an Observable interfacebecause there is no Observable interface.

Page 20: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.20

Weaknesses

What if you have a class that is already in a class hierarchy and also needs to play the role of an Observable?

Since Java doesn't support multiple inheritance, you're out of luck. That class cannot extend from Observable because it is already extending from some other class.

It also means that you are stuck with the one and only implementation of Observable in java.util.Observable. For a variety of reasons, you may want to use an alternate implementation - e.g., to do the notification in a separatethread or in a particular order. You may even want to vary the implementation of Observable at runtime. There is no Observable interface for your alternate implementations to implement. You cannot reuse Observable by composition soyou cannot vary the composed Observable implementation at runtime.

Page 21: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.21

Weaknesses

The designers of the Observable class broke two general principles of object-oriented design with Java:

1. The first principle is to design with interfaces rather than classes. Whenever possible, avoid committing yourself to a particular implementation of an interface.

2. The second principle is to favor reuse by composition over reuse by inheritance unless a class hierarchy is clearly indicated.

By omitting an Observable interface and making some of its methods protected, the designers made it impossible to reuse Observable by composition.

Page 22: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.22

Weaknesses

A minor weakness in Observable is the necessity to call setChanged() before notifySubscribers().

The intention there seems to be to eliminate needless notifications in cases where there is no interesting change to the Observable.

There may be situations in which this two-stage notification is appropriate, but it isn't the simplest case and programmers shouldn't be forced to use this implementation in all situations. Also, setChanged() is protected, further reinforcing the necessity to reuse the class only by inheritance.

Page 23: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.23

Weaknesses

The main weakness in the Observer interface is its tight coupling with the Observable class.

The first parameter to the update() method is unnecessarily typed as an Observable. If it were typed more generally as a simple Object, the Observer interface would be more reusable. It then could be used with any Observable implementation or even in any situation, completely unrelated to Observer/Observable, which called for a void method with two Object parameters.

Page 24: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.24

Possible Solutions

The general opinion is that one should re-use a better/improved Observer.

Many such improved Observers exist (the versionby Coad and Mayfield is perhaps the best known)

You should be able to write your own!

ReferencesGamma, E., Johnson, R. and Vlissides, J., "Design Patterns:Elements of Object-Oriented Architecture", Addison-Wesley,Reading, MA, 1995.

Coad , P. and Mayfield, M., "Java Design: Building BetterApps and Applets", Yourdon Press, Upper Saddle River, NJ,1997.

Page 25: TO DO:   Create  a new class  which adds statistics  to the  dice

2013: J Paul Gibson TSP: Object Oriented Development CSC7322/DesignII.25

TO DO

Write your own Observable interface

Using this interface, make an Observable Dice.

Make 2 views: Horizontal and Vertical histograms (you should already have the code for these!)

Let these views observe the observable Dice (and update their output accordingly)

QUESTION: did your code maximise re-use and re-usability?If not, restructure the code (design)