Refactoring Programs (Again)


This project is intended to get you to practice some of the programming and design techniques discussed in class recently and consists of four activities:

The code to simulate a game of roulette is given below although you will focus your efforts on Game class (declared in game.h and implemented in game.cpp).

Understanding

You should analyze the code above and determine the purpose of each of the classes written (i.e., what role does it play in the program). There are some comments currently in the code, but your analysis should go beyond these comments. However, it should not be necessary to write more than a paragraph for each class. In order to determine each class' role, you should focus on how it interacts with other classes in the program or how a particular task is accomplished.

To help direct your analysis, consider the following questions:

  1. Why is it not necessary for game.h to include iostream?
  2. Why is Bet a struct and not a class?
  3. How many classes know about the Bet struct?
  4. What code would be need to be added to game to allow the user to make another kind of bet that paid one to one odds and was based on whether the number spun was high, between 19 and 36, or low, between 1 and 18?
  5. What code would need to be changed to add error checking to the characters input by the user to choose a bet?

Refactoring

You should examine the code given and refactor it to remove as much of the conditional logic in the play function as possible with an inheritance hierarchy of bets. Your refactored code should attempt to minimize the amount of new code required to add another type of bet. You may create (and comment) any new classes you want to solve this problem.

To help direct your refactoring, consider the following questions:

  1. What functions would make sense as behaviors of a Bet hierarchy (i.e., make bets open to extension)? 
  2. What functions would help improve the code in the play function (i.e., close it to modification)?
  3. What functions can be completely implemented in the Bet super-class (i.e., are constant across the hierarchy), and which completely in the Bet sub-classes (i.e., must be specialized across the hierarchy)?
  4. Should Bet remain a struct or be re-implemented as a class?
  5. How should the Game class create the correct Bet sub-class?

Testing

You should provide a set of tests that verify your modified program still works as intended. Tests can be in the form of input data files, driver programs, or other classes that verify every line of code written works as intended.

To help direct your testing, consider the following questions:

  1. How can you test a program that is primarily based on randomness?
  2. How can you easily remove the randomness?
  3. Can you make it easy to turn randomness on and off?
  4. Can you make it easy to test several different kinds of bets?
  5. How should you package your testing code so that it is easy to run repeatedly?

Improving

Finally, using your improved code, you should add the three bets given in the original specification not implemented code given to you, adding as little new code as possible.

Compare the effort to create a new bet in your improved code to how you would have done it in the original code.

  1. In what ways is the refactored code simpler?
  2. In what ways is the refactored code more complex?
  3. What trade-offs did you make when refactoring your old code?
  4. Which code do you prefer and why?

Comments?