Flylib.com

Books Software

 
 
 

Section 3.9. Object-Oriented Design: Inheritance and Polymorphism


[Page 135 ( continued )]

3.9. Object-Oriented Design: Inheritance and Polymorphism

This use of Object 's toString() method provides our first look at Java's inheritance mechanism and how it promotes the generality and extensibility of the object-oriented approach. As a subclass of Object , our OneRowNim class automatically inherits toString() and any other public or protected methods defined in Object . We can simply use these methods as is, insofar as they are useful to us. As we saw in this case, the default version of toString() was not very useful. In that case, we can override the method by defining a method in our class with the exact same method signature. The new version of toString() can be customized to do exactly what is most appropriate for the subclass.

Inheritance


One of the great benefits of the object-oriented approach is the ability to define a task, such as toString() , at a very high level in the class hierarchy and let the inheritance mechanism spread the task throughout the rest of the hierarchy. Because toString() is defined in Object , you can invoke this method for any Java object. Moreover, if you override toString() in the classes you define, you will be contributing to its usefulness . Two important lessons from this example are

Effective Design: Inheritance

The higher up in the class hierarchy that a method is defined, the more widespread its use can be.


Effective Design: Overriding toString()

The toString() method can be overridden in any user -defined Java class. It is a useful thing to do in any class where the state of an object can be defined briefly .


Obviously there is much more that needs to be explained about Java's inheritance mechanism. Therefore, we will frequently revisit this topic in subsequent chapters.


[Page 136]

Another important concept of object-oriented design is polymorphism. The toString() method is an example of a polymorphic method. The term polymorphism is from the Greek terms poly , which means "many," and morph , which means "form." The toString() method is polymorphic because it has different behaviors when invoked on different objects.

For example, suppose we design a class, Student , as a subclass of Object and define its toString() method to return the student ID number. Given this design, then obj.toString() will return a student ID if obj is an instance of Student , but if it is an instance of OneRowNim , it will return the description of its state that we defined above. The following code segment illustrates the point:

Object obj;

// obj can refer to any Object

obj =

new

Student("12345");

// obj refers to a Student

System.out.println(obj.toString());

// Prints "12345"

obj =

new

OneRowNim(11);

// obj refers to a OneRowNim

System.out.println(obj.toString());

// Prints: nSticks = 11, player = 1


In this case, the variable obj is used to refer to a Student and then to a OneRowNim instance. This is okay because both classes are subclasses of Object . When toString() is invoked on obj , Java will figure out what subclass of Object the instance belongs to and invoke the appropriate toString() method.



[Page 136 ( continued )]

3.10. Drawing Lines and Defining Graphical Methods (Optional)

We used a Graphics object in Chapter 2 to draw rectangles and ovals in an applet window. The Graphics class also possesses a method for drawing a line segment. Problems involving drawing pictures in an applet window using a series of line segments can be a source of examples of defining useful methods and also of making good use of loops .

The Graphics class has a public instance method with the header:


public  void

drawLine(

int

x1,

int

y1,

int

x2,

int

y2)


The method call g.drawLine(x1, y1, x2, y2) draws a line from the point ( x 1, y 1) to ( x 2, y 2), where ( x , y ) refers to a point that is x pixels from the left edge of the area that g is drawing in and y pixels from the top edge. Thus g.drawLine(10, 10, 10, 60) draws a vertical line segment that is 50 pixels long and 10 pixels from the left edge of the drawing area, that is, a line segment from the point (10, 10) to the point (10, 60).

Consider the problem of creating an applet program with a method called drawSticks() to draw any specified number of vertical line segments. This method might be useful for an applet user interface to the OneRowNim game to draw the number of sticks at a given point in a game. Suppose that this method must have an int parameter to specify the number of vertical lines to draw and two int parameters to specify the location of the top endpoint of the leftmost line segment. The drawSticks() method will need to use a Graphics object connected to the applet window for drawing the line segment. The only such Graphics object available is the parameter in the paint() method of an applet. Thus the method must have a Graphics parameter, and it will be called in the paint() method using the Graphics object there as an argument. Thus the header of the method should look like:


[Page 137]


public void

drawSticks(Graphics g,

int

x,

int

y,

int

num)


The length of the line segments and the distance between them are not specified by parameters, so we need to choose some fixed values for these quantities . Let us assume that the line segments are 10 pixels apart and 50 pixels long. We now have enough information to complete the definition of an applet to solve this problem. Such a class definition is reproduced in Figure 3.19.

Figure 3.19. An applet program with a method for drawing a set of sticks.

/**


* DrawLineApplet demonstrates some graphics commands.


* It draws a set of 12 vertical lines and a set of 7 lines.


*/


import

java.awt.*;

import

java.applet.*;

public class

DrawSticksApplet

extends

Applet

/**


* drawSticks(g,x,y,num) will draw num vertical line


* segments. The line segments are 10 pixels apart and


* 50 pixels long. The top endpoint of the left most


* line segment is at the point (x,y).


*/


public void

drawSticks(Graphics g,

int

x,

int

y,

int

num)
   {

int

k = 0;

while

(k < num)
        {   g.drawLine(x, y, x, y + 50);
            x = x + 10;
            k = k + 1;
        }

// while

}

// drawSticks()


public void

paint(Graphics g)
   {   drawSticks(g, 25, 25, 12);
       g.setColor(Color.cyan);
       drawSticks(g, 25, 125, 7);
   }

// paint()

}

// DrawSticksApplet class


Note that the body of drawSticks() uses a while loop to draw the lines, and declares and initializes a local variable to zero to use for counting the number of lines drawn. The statement g.drawLine(x, y, x, y + 50); draws a vertical line 50 pixels long. Increasing the value of x by 10 each time through the loop moves the next line 10 pixels to the right.

The first call to drawSticks() in the paint() method draws 12 lines with (25,25) the top point of the leftmost line. The second call to drawSticks() will draw seven cyan sticks 100 pixels lower. Note that changing the color of g before passing it as an argument to drawSticks() changes the drawing color.


[Page 138]

To run this applet, one needs the following HTML document, which specifies the applet code as DrawSticksApplet.class :

<HTML>
<HEAD>
<TITLE> Draw Sticks Web Page</TITLE>
</HEAD>
<BODY>
<H2> DrawSticksApplet will appear below.</H2>
<APPLET CODE = "DrawSticksApplet.class"
               WIDTH = 400 HEIGHT = 200>
</APPLET>
</BODY>
</HTML>


An image of the DrawSticksApplet as it appears in a browser window is shown in Figure 3.20.

Figure 3.20. The DrawSticksApplet as displayed in a browser window.


As we have seen in this example, defining methods with parameters to draw an object makes the code reusable and makes it possible to draw a complex scene by calling a collection of simpler methods. It is a typical use of the divide-and-conquer principle. The while loop can be useful in drawing almost any geometrically symmetric object.