We'll present the design modification for
Wheel first. This will be followed by design
information for NonRandom in both Java and
Python.
Wheel contains the 38 individual bins
on a Roulette wheel, plus a random number generator. It can select a
Bin at random, simulating a spin of the
Roulette wheel.
Note that we will be rewriting these methods to change their implementation. The definitions of the methods don't change, but the implementations can (and do) change. This is the real strength of OO design. Once we have a well-defined interface (defined by the public methods and attributes), we are free to change the implementation as necessary.
This kind of rework — making a fundamental change to the implementation without touching the interface — is essential to successful OO programming.
Java: java.util.Vector bins = new Vector( 38 );
Python: bins = 38*[None]
Contains the individual Bin
instances.
Java: java.util.Random rng = new java.util.Random();
Python: rng = random.Random()
Generates the next random number, used to select a
Bin from the bins
collection.
Wheel();This will also create a new random number generator instance. It will then use the other constructor to do the rest of the initialization.
Wheel(Random rng);Creates a new wheel with 38 empty
Bins. It will use the given random
number generator instance.
addOutcome(int number,
Outcome outcome);Adds the given Outcome to the
Bin with the given number.
next();Generates a random number between 0 and 37, and returns
the randomly selected Bin.
Java: Be sure to note that the
java.util.Random
nextInt method uses the size of the
bins collection to return values from 0 to
the size of the collection. Typically there are 38 values,
numbered from 0 to 37.
Python: the choice function will
select one of the available Bins from
the bins list.
Bin getBin(int aBin);Returns the given Bin from the
internal collection.
We need a controlled kind of random number generation for
testing purposes. We'll define a class
NonRandom that extends
java.util.Random, but provides a more
testable sequence of values. One approach is to simply count through
a range of integer vales.
The API documentation gives us the advice
that the protected int next(int bits); generates the next pseudorandom number. It says
that any subclass should override this, as this is used by all other
methods.
NonRandom();This is the default constructor, and will initialize
value to zero.
NonRandom(long seed);This constructor ignores the seed value. It initializes
value to zero.
Nonrandom module provides the same
interface as random.Random, but merely counts
through a range of integer vales.
The API documentation gives us the advice
that a subclass should override the
random(), seed(),
getstate(),
setstate() and
jumpahead() methods. However, we can safely
ignore all but the random() method
itself.
def NonRandom(self):This is the default constructor, and will initialize
value to zero.
def NonRandom(self, seed):This constructor ignores the seed value. It initializes
value to zero.
def random(self):This method is the heart of the generator. In our case, we simply add 1 to the value and return (value % 38)/38.0 . This provides a predicable sequence of values that is suitable for our testing.
The return value does two things. First, it computest the remainder when the value is divided by 38. This will be a value from 0 to 37. Then it divides this by 38 to return a floating-point number in the half-open range [0.0, 1.0), as required by the API. This means that 0.0 is included, but 1.0 is not included.