CS 101
Computer Science 1 in Java
Prof. Alvarez

Object-Oriented Modeling using Instantiable Classes

The Java language follows an objected-oriented approach. This means that it uses objects to model data items. Objects are grouped into classes. The objects of a class share similar properties and behaviors.

Example of Object-Oriented Modeling: the Dice Table

Consider a game involving rolling standard six-sided dice on a table as shown below. The table can accomodate zero, one, or more dice. There are three basic operations that can be carried out with a die: creation, rolling, and deletion. Dice must first be placed on the table ("created"). Any die that is on the table may be rolled. The newest die on the table may be taken off the table ("deleted"). The images below show the result of rolling die number 5, which is located in the lower left corner of the table.


Creating a die

Initial table configuration

Initially, the dice table is empty.

Dice can be created (and brought onto the table) by pressing the "Create Die" button.

After pressing the "Create Die" button

Additional dice may be brought onto the table by repeatedly pressing "Create Die". One may also delete the last die by pressing the corresponding button.


Rolling a die

Since there may be multiple dice on the table, rolling a die requires that the number of the die be specified. This is done by writing the number in the text field located in the top right corner of the table. The "Roll Die" button should then be pressed.

Before rolling

After rolling

Rolling a die results in a random face number between 1 and 6 being assigned to the chosen die.


Objects and classes in the DiceTable program

The RollingDie class

Notice that all dice are created equal in the sense that they share a common set of behaviors. Namely, they all have 6 sides and exist solely for the purpose of being rolled. Because of this, we define a class named RollingDie. Each instance of the RollingDie class represents a single die. The RollingDie class represents the abstract concept of a die that can be rolled. To create an instance of the RollingDie class, the constructor method of the class is invoked, using the keyword new followed by the class name RollingDie() (note the parentheses). Once created, each individual instance of the RollingDie class "understands" a method (message) named roll() that causes a die to randomly select a face between 1 and 6 when it receives the roll() message.

The Javadoc documentation for the RollingDie class describes additional details.

The DiceTable class

The playing table shown above contains several individual dice. Each of these dice is represented by an instance of the RollingDie class. The table itself is in turn an instance of a separate class, DiceTable. The DiceTable class is a "client" of the RollingDie class, in the sense that RollingDie instances are used within the DiceTable class. As with RollingDie, it is also possible to create instances of the DiceTable class. A DiceTable instance represents a playing table with zero, one, or more dice on it. It allows the human player to place new dice on the table, roll an existing die, or delete the most recently created die. When a human player interacts with the table program, he/she is really using an instance of the DiceTable class.


Sample client code of the RollingDie class

Before taking a look at how the RollingDie class can be implemented (written), consider how to use the class within a client program. Basically, a client program such as DiceTable will create one or more instances of the RollingDie class and send them messages in order to achieve a desired effect. Here's an example involving repeatedly rolling two dice until a sum of 12 is obtained:
	RollingDie lucky = new RollingDie();
	RollingDie trusty = new RollingDie();
	int rollCount = 0;
	while (lucky.getFace() + trusty.getFace() != 12) {
		lucky.roll();
		trusty.roll();
		rollCount++;
	}
	System.out.println("You rolled a 12 in only " + rollCount + " tries");
Notice that the precise way in which RollingDie is written should not concern the writer of the client program, as long as he or she trusts that the behaviors described in the specification of the RollingDie class will be provided as promised.


Inside the RollingDie class

Now consider how to implement (write) the RollingDie class so that it provides the behaviors that client programs will be relying on. A simple implementation of the RollingDie class is shown below. This implementation provides the behaviors that are exhibited by individual dice in the DiceTable program. A discussion follows.
public class RollingDie {

	// private instance variables; each RollingDie instance
	// has its own copy of each of these instance variables
	private int numberOfSides, face;

	// constructor method; creates a six-sided RollingDie instance
	public RollingDie() {
		numberOfSides = 6;
		roll();
	}

	// getFace() returns the face that is currently showing on the recipient
	// the recipient instance is not modified by getFace()
	public int getFace() {
		return face;
	}

	// getIcon() returns a graphical representation of the current face
	public ImageIcon getIcon() {
                if (face==1)
                        return new ImageIcon("one.jpg");
                else if (face==2)
                        return new ImageIcon("two.jpg");
                else if (face==3)
                        return new ImageIcon("three.jpg");
                else if (face==4)
                        return new ImageIcon("four.jpg");
                else if (face==5)
                        return new ImageIcon("five.jpg");
                else if (face==6)
                        return new ImageIcon("six.jpg");
                else 
			return new ImageIcon();
        }

	// roll() randomly assigns a face value to the recipient instance
	// the recipient instance is potentially modified by roll()
	public int roll() {
		face = (int) (numberOfSides*Math.random() + 1);
		return getFace();
	}

}

Instance variables

Every instance of an instantiable class like RollingDie has internal variables that store state information for that instance. These internal variables are called instance variables. Syntactically, there are two determining factors in making a variable an instance variable:
  1. the variable should be declared inside the class body but outside the bodies of all of the methods of the class
  2. the variable's declaration should not include the keyword static.
Instance variables are declared once, within the class definition, in accordance with the above. However, every instance of the class will have its own copy of each instance variable. Information can be read from and written into an object's instance variables by sending the object messages embodied as invocations of the instance methods of the class.

Methods

An instantiable class like RollingDie has three basic kinds of instance-related methods: constructors, selectors (accessors), and modifiers (mutators). All of these methods must be declared without using static in the header.
  1. Constructors allow new instances of the class to be created. The name of a constructor must match the name of the class exactly, and no return type should be provided in the constructor header:
    	// constructor method; creates a six-sided RollingDie instance
    	public RollingDie() {
    		numberOfSides = 6;
    		roll();
    	}
    
  2. Selectors provide read-only access to the information in the recipient instance's instance variables:
    	// getFace() returns the face that is currently showing on the recipient
    	// the recipient instance is not modified by getFace()
    	public int getFace() {
    		return face;
    	}
    
  3. Modifiers provide read-write access to the information in the recipient instance's instance variables:
    	// roll() randomly assigns a face value to the recipient instance
    	// the recipient instance is potentially modified by roll()
    	public int roll() {
    		face = (int) (numberOfSides*Math.random() + 1);
    		return getFace();
    	}