1 / 25

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

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.

kailey
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. TO DO: Create a new class whichaddsstatistics to the dice This class shouldaddfunctionality to store the roll frequencies. You shouldimplement a validation test (as well as running unit tests) as below: NOTE: Don’tforget to runregression tests TSP: Object OrientedDevelopment

  2. TO DO: Implement 2 different designs //using inheritance publicclass DiceWithStatistics1 extends Dice implementsDiceWithStatisticsSpecification{ //… } //using composition publicclass DiceWithStatistics2 implementsDiceWithStatisticsSpecification{ //… protectedDicedice; //… } If you have not developedyourown solution code thenyoushouldtry to understandmysample solution, whichcanbedownloadedfrom the module web site: Dice-WithStatistics.zip TSP: Object OrientedDevelopment

  3. Specificationusing an interface package abstractions; publicinterfaceDiceWithStatisticsSpecificationextendsDiceSpecification{ publicabstractintfrequencyOfRoll(int side) throwsIllegalArgumentException; publicabstractboolean invariant(); publicabstractvoid roll(); public String toString(); } Note: Javadoccomments – not on the transparency, but included in the code – are used to update the documentation for the statisticsspecification TSP: Object OrientedDevelopment

  4. TO DO: Implementationusing 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> */ publicclass DiceWithStatistics1 extends Dice implementsDiceWithStatisticsSpecification { /** * Stores the number of times each side of the dice has been rolled */ protectedintrollsFrequency []; TSP: Object OrientedDevelopment

  5. TO DO: Implementationusing 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 = newint [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} .. • * {@linkDiceSpecification#MAXIMIM_numberOfSides}) • */ • public DiceWithStatistics1 (intsides){ • super(sides); • rollsFrequency = newint [NUMBEROFSIDES]; • resetFrequencies(); • numberOfDieWithStatistics++; • } TSP: Object OrientedDevelopment

  6. TO DO: Implementationusing inheritance publicboolean invariant(){ if (rollsFrequency==null ) returnfalse; if (rollsFrequency.length < NUMBEROFSIDES) returnfalse; for (int i =0; i<NUMBEROFSIDES; i++) if (rollsFrequency[i] <0) returnfalse; returnsuper.invariant(); } QUESTION: Could/Shouldthis invariant beimplemented in an abstract class? TSP: Object OrientedDevelopment

  7. TO DO: Implementationusing inheritance • /** • * rolls the dice, updates the lastRoll value and updates the frequency history • */ • publicvoid 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 • */ • publicintfrequencyOfRoll(int side) throwsIllegalArgumentException{ • if (side <=0 || side > MAXIMIM_numberOfSides) • throw (newIllegalArgumentException("The number of sides specified is not valid")); • returnrollsFrequency[side-1]; • } TSP: Object OrientedDevelopment

  8. TO DO: Implementationusing 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"; returnstr; } QUESTION: Could/Shouldthismethodbeimplemented in an abstract class? TSP: Object OrientedDevelopment

  9. TO DO: Implementationusing 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> */ publicclass DiceWithStatistics2 implementsDiceSpecification{ protectedDicedice; /** * The number of dieWithStatistics objects that are currently instantiated<br> * We decrement this value when a DiceWithStatistics1 destructor is called - */ protectedstaticintnumberOfDieWithStatistics = 0; /** * Stores the number of times each side of the dice has been rolled */ protectedintrollsFrequency []; TSP: Object OrientedDevelopment

  10. TO DO: Implementationusing 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 = newDice(); rollsFrequency = newint [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} .. * {@linkDiceSpecification#MAXIMIM_numberOfSides}) * <br> If it is not in range use the default number of sides ({@link DiceSpecification#DEFAULT_numberOfSides}) */ publicDiceWithStatistics2 (intsides){ dice = newDice(sides); rollsFrequency = newint [dice.numberOfSides()]; resetFrequencies(); numberOfDieWithStatistics++; } TSP: Object OrientedDevelopment

  11. TO DO: Implementationusing composition publicintlastRoll (){ returndice.lastRoll();} publicintnumberOfSides(){ returndice.numberOfSides();} publicintnumberOfRolls(){ returndice.numberOfRolls();} /** * Decrement the count for the number of current DiceWithStatistics that are instantiated */ protectedvoid finalize() throwsThrowable{ numberOfDieWithStatistics--;} TSP: Object OrientedDevelopment

  12. TO DO: Implementationusing composition • publicboolean invariant(){ • if (rollsFrequency==null ) dice.invariant(); • else • for (int i =0; i<dice.numberOfSides(); i++) • if (rollsFrequency[i] <0) returnfalse; • returntrue; • } • publicvoid roll(){ • dice.roll(); • rollsFrequency[lastRoll()-1] = rollsFrequency[lastRoll()-1]+1; • } • publicintfrequencyOfRoll(int side) throwsIllegalArgumentException{ • if (side <=0 || side > numberOfSides()) • throw (newIllegalArgumentException("The number of sides specified is not valid")); • returnrollsFrequency[side-1]; • } TSP: Object OrientedDevelopment

  13. TO DO: Implementationusing 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"; • returnstr; • } Note: thisisverysimilar to the toStringmethod in the inheritancebased 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"; returnstr; } QUESTION: how to factor out the cut-and-paste code? TSP: Object OrientedDevelopment

  14. TO DO: Write tests for both designs • Unit tests • Validation tests • Maximise re-use • Maximise re-usability • Minimizecut-and-pasteprogramming TSP: Object Oriented Development

  15. TO DO: Create2 different terminal/console views The frequenciescaneitherbedisplayedvertically or horizontally. (OPTIONAL: If the frequency values are biggerthan the height/width of the screenthenyoushouldscalethem in order to occupy as much of the screen as possible. The screen size shouldbestored in constant variables HEIGHT and WIDTH.) 10.0 * * * * * * * * * * * * * * * * * * * * ** * * * ** * * * ** * * * *** ** ** * * *** ** ** * * *** ***** * * * *** ***** * * * *** ********* ***** ********* ***** ********* ***** ********* ***** ********* ***** 1.0 --------------- 123456789111111 012345 1 |******** 2 |****** 3 |*** 4 |**** 5 |****** 6 |** 7 |*** 8 |** 9 |***** 10 | 11 |***** 12 |** 13 |******** 14 |***** 15 |*********10.0 1.0 DISCUSSION: How to best includetheseviews in the design? TSP: Object OrientedDevelopment

  16. The consequences of the initial design decision– Choosing to implement a DiceWithStatistics as a subclass of Diceis a design decisionthatmayhave consequencies on later stages of the development. The alternative re-use mechanismwas to design a DiceWithStatistics class/object to have a Dice component class/object. This alsomayhave consequencies on later stages of the development DISCUSSION: What are the possible consequences (positive and negative)? CLUE: You may have seenthemwhenweconsidered the differentviews OBSERVERS: Wemaywish to createdifferentviewsthatautomatically update when the state of the models changes TSP: Object OrientedDevelopment

  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. TSP: Object OrientedDevelopment

  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 TSP: Object OrientedDevelopment

  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. TSP: Object OrientedDevelopment

  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. TSP: Object OrientedDevelopment

  21. Weaknesses The designers of the Observable class broke two general principles of object-oriented design with Java: The first principle is to design with interfaces rather than classes. Whenever possible, avoid committing yourself to a particular implementation of an interface. 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. TSP: Object OrientedDevelopment

  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. TSP: Object OrientedDevelopment

  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. TSP: Object OrientedDevelopment

  24. Possible Solutions The general opinion isthat one shouldre-use a better/improved Observer. ManysuchimprovedObserversexist (the versionbyCoad and Mayfield isperhaps the best known) You shouldbe able to writeyourown! 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. TSP: Object OrientedDevelopment

  25. TO DO Writeyourown Observable interface Usingthis interface, make an Observable Dice. Make 2 views: Horizontal and Vertical histograms (youshouldalready have the code for these!) Let theseviews observe the observable Dice (and update their output accordingly) QUESTION: didyour code maximise re-use and re-usability? If not, restructure the code (design) TSP: Object Oriented Development

More Related