This chapter will present the design for the Bin class. In addition to that, we’ll examine the collection classes available in Java and Python. We’ll also present present some questions and answers on this particular class and the process of creating a design.
The Roulette wheel has 38 bins, identified with a number and a color. Each of these bins defines a number of closely related winning Outcome s. At this time, we won’t enumerate each of the 38 Bins of the wheel and each of the winning Outcomes (from two to fourteen in each Bin); we’ll save that for a later exercise.
At this time, we’ll define the Bin class, and use this class to contain a number of Outcome objects.
Two of the Bins have relatively few Outcomes. Specifically, the 0 Bin only contains the basic “0” Outcome and the “00-0-1-2-3” Outcome . The 00 Bin , similarly, only contains the basic “00” Outcome and the “00-0-1-2-3” Outcome .
The other 36 Bins contain the straight bet, split bets, street bet, corner bets, line bets and various outside bets (column, dozen, even or odd, red or black, high or low) that will win if this Bin is selected. Each number bin has from 12 to 14 individual winning Outcomes.
Some Outcomes, like “red” or “black”, occur in as many as 18 individual Bins. Other Outcomes, like the straight bet numbers, each occur in only a single Bin. We will have to be sure that our Outcome objects are shared appropriately by the Bins.
Since a Bin is just a collection of individual Outcome objects, we have to select a collection class to contain the objects. In Java we have five basic choices, with some variations based on performance needs. In Python, we have two basic choices.
There are five basic Python types that are a containers for other objects.
Having looked at the fundamental collection varieties, we will elect to use a frozenset.
Why wasn’t Bin in the design overview?
The definition of the Roulette game did mention the 38 bins of the wheel. However, when identifying the nouns, it didn’t seem important. Then, as we started designing the Wheel class, the description of the wheel as 38 bins came more fully into focus. Rework of the preliminary design is part of detailed design. This is the first of several instances of rework.
Why introduce an entire class for the bins of the wheel? Why can’t the wheel be an array of 38 individual arrays?
There are two reasons for introducing Bin as a separate class: to improve the fidelity of our object model of the problem, and to reduce the complexity of the Wheel class. The definition of the game describes the wheel as having 38 bins, each bin causes a number of individual Outcomes to win. Without thinking too deeply, we opted to define the Bin class to hold a collection of Outcomes. At the present time, we can’t foresee a lot of processing that is the responsibility of a Bin. But allocating a class permits us some flexibility in assigning responsibilities there in the future.
Additionally, looking forward, it is clear that the Wheel class will use a random number generator and will pick a winning Bin. In order to keep this crisp definition of responsibilities for the Wheel class, it makes sense to delegate all of the remaining details to another class.
Isn’t an entire class for bins a lot of overhead?
The short answer is no, class definitions are almost no overhead at all. Class definitions are part of the compiler’s world; at run-time they amount to a few simple persistent objects that define the class. It’s the class instances that cause run-time overhead.
In a system where were are counting individual instruction executions at the hardware level, this additional class may slow things down somewhat. In most cases, however, the extra few instructions required to delegate a method to an internal object is offset by the benefits gained from additional flexibility.
How can you introduce Set, List, Vector when these don’t appear in the problem?
We have to make a distinction between the classes that are uncovered during analysis of the problem in general, and classes are that just part of the implementation of this particular solution. This emphasizes the distinction between the problem as described by users and a solution as designed by software developers. The collections framework are part of a solution, and hinted at by the definition of the problem. Generally, these solution-oriented classes are part of frameworks or libraries that came with our tools, or that we can license for use in our application. The problem-oriented classes, however, are usually unique to our problem.
Bin contains a collection of Outcomes which reflect the winning bets that are paid for a particular bin on a Roulette wheel. In Roulette, each spin of the wheel has a number of Outcome s. Example: A spin of 1, selects the “1” bin with the following winning Outcomes: “1” , “Red” , “Odd” , “Low” , “Column 1” , “Dozen 1-12” , “Split 1-2” , “Split 1-4” , “Street 1-2-3” , “Corner 1-2-4-5” , “Five Bet” , “Line 1-2-3-4-5-6” , “00-0-1-2-3” , “Dozen 1” , “Low” and “Column 1” . These are collected into a single Bin .
Python programmers should provide an initializer that uses the * modifier so that all of the individual arguments appear as a single list within the initializer.
| Parameter: | outcomes – any number of outcomes used to populate the Bin initially. |
|---|
This constructor can be used as follows.
Python Bin Construction
five= Outcome( "00-0-1-2-3", 6 )
zero= Bin( Outcome("0",35), five )
zerozero= Bin( Outcome("00",35), five )
Adds an Outcome to this Bin. This can be used by a builder to construct all of the bets in this Bin. Since this class is really just a façade over the underlying collection object, this method could simply delegate the real work to the underlying collection.
Note that a frozenset is immutable; unlike a list it does not have an append() method. Instead, a new frozenset can be constructed by using the | operator which creates a new frozenset from a frozenset and a frozenset or set
>>> zero= Outcome("0",35)
>>> zerozero= Outcome("00",35)
>>> b = frozenset( [zero] )
>>> b
frozenset([<roulette.Outcome object at 0x6002d0>])
>>> map(str,b)
['0 (35:1)']
>>> b |= set( [zerozero] )
>>> map(str,b)
['0 (35:1)', '00 (35:1)']
>>> b
frozenset([<roulette.Outcome object at 0x6002d0>, <roulette.Outcome object at 0x600330>])
| Parameter: | outcome (Outcome) – An outcome to add to this Bin |
|---|
An easy-to-read representation of the list of Outcomes in this Bin.
A handy technique for displaying collections is the following. This maps the str() function to each element of Bin.outcomes, then joins the resulting string with ", " separators
', '.join( map(str,self.outcomes) )
| Returns: | String of the form [outcome, outcome, ...]. |
|---|---|
| Return type: | str |
There are two deliverables for this exercise. Both will have Javadoc comments or Python docstrings.
The Bin class.
A class which performs a unit test of the Bin class. The unit test should create several instances of Outcome, two instances of Bin and establish that Bin s can be constructed from the Outcomes.
Programmers who are new to OO techniques are sometimes confused when reusing individual Outcome instances. This unit test is a good place to examine the ways in which object references are shared. A single Outcome object can be referenced by several Bins. We will make increasing use of this in later sections.