Presentation is loading. Please wait.

Presentation is loading. Please wait.

2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.1 TO DO: Create a new class which adds statistics to the dice This class should add.

Similar presentations


Presentation on theme: "2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.1 TO DO: Create a new class which adds statistics to the dice This class should add."— Presentation transcript:

1 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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

2 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.2 TO DO: Implement 2 different designs //using inheritance public class DiceWithStatistics1 extends Dice implements DiceWithStatisticsSpecification{ //… } //using composition public 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

3 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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

4 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.4 TO DO: Implementation using inheritance /** * * This class extends the behaviour of the {@link Dice} with * statistics for frequency of rolls * These statistics are viewable through an updated toString method * * @author J Paul Gibson * @version 1 * * Design decision - use inheritance to extend already existing Dice behaviour * Implementation decision - store the roll frequencies in an array of integers * */ public class DiceWithStatistics1 extends Dice implements DiceWithStatisticsSpecification { /** * Stores the number of times each side of the dice has been rolled */ protected int rollsFrequency [];

5 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.5 TO DO: Implementation using inheritance /** * Create a default dice and reset the roll frequencies for each side to be 0 * Increment the count for the numberOfDieWithStatistics */ public DiceWithStatistics1 (){ super(); rollsFrequency = new int [NUMBEROFSIDES]; resetFrequencies(); numberOfDieWithStatistics++; } /** * Create a dice and reset the roll frequencies for each side to be 0 * Increment the count for the numberOfDieWithStatistics * @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++; }

6 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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?

7 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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 MAXIMIM_numberOfSides) throw (new IllegalArgumentException("The number of sides specified is not valid")); return rollsFrequency[side-1]; }

8 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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?

9 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.9 TO DO: Implementation using composition /** * * This class extends the behaviour of the {@link Dice} with statistics for * frequency of rolls * These statistics are readable through the toString method * * @author J Paul Gibson * @version 1 * * Design decision - use composition to re-use already existing Dice behaviour * Implementation decision - store the roll frequencies in an array of integers * */ public class DiceWithStatistics2 implements DiceSpecification{ protected Dice dice; /** * The number of dieWithStatistics objects that are currently instantiated * 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 [];

10 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.10 TO DO: Implementation using composition /** * Create a new DiceWithStatistics2 and reset the roll frequencies for each side to be 0 * The number of sides is set by default to {@link DiceSpecification#DEFAULT_numberOfSides} * Increment the count for the numberOfDieWithStatistics */ 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 * Increment the count for the numberOfDieWithStatistics * @param sides can specify the number of sides * (within range of {@link DiceSpecification#MINIMUM_numberOfSides}.. * {@link DiceSpecification#MAXIMIM_numberOfSides}) * 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++; }

11 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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--;}

12 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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 numberOfSides()) throw (new IllegalArgumentException("The number of sides specified is not valid")); return rollsFrequency[side-1]; }

13 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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?

14 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.14 TO DO: Write tests for both designs Unit tests Validation tests Maximise re-use Maximise re-usability Minimize cut-and-paste programming

15 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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?

16 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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

17 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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 heavy use of a variant of this pattern in the 1.1 AWT event delegation 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.

18 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.18 The Observer Design Pattern: UML The idea of the pattern is to model a one-to-many dependency without tightly coupling the observed object with its many observers. When the observed object changes in some interesting way it can automatically notify all of its observers without knowing them directly

19 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.19 Weaknesses Unfortunately, a number of weaknesses have been identified in 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; or rather, that it is a class without a corresponding interface. This implies that the only way to reuse Observable is to subclass it. You can't take an existing class and tack on the role of Observable by having it implement an Observable interface because there is no Observable interface.

20 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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 separate thread 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 so you cannot vary the composed Observable implementation at runtime.

21 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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.

22 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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.

23 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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.

24 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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! References Gamma, 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 Better Apps and Applets", Yourdon Press, Upper Saddle River, NJ, 1997.

25 2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/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)


Download ppt "2013: J Paul GibsonTSP: Object Oriented DevelopmentCSC7322/DesignII.1 TO DO: Create a new class which adds statistics to the dice This class should add."

Similar presentations


Ads by Google