Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AhmadLang / Java, How To Program, 2004

.pdf
Скачиваний:
630
Добавлен:
31.05.2015
Размер:
51.82 Mб
Скачать

After instantiation: number: 0; string: Hello

After changing values: number: 77; string: Goodbye

In the PackageData class declaration, lines 2627 declare the instance variables number and string with no access modifierstherefore, these are package-access instance variables. The PackageDataTest application's main method creates an instance of the PackageData class (line 9) to demonstrate the ability to modify the PackageData instance variables directly (as shown on lines 1516). The results of the modification can be seen in the output window.

[Page 396 (continued)]

8.18. (Optional) GUI and Graphics Case Study: Using Objects with Graphics

Most of the graphics you have seen to this point did not vary each time you executed the program. However, Exercise 6.2 asked you to create a program that generated shapes and colors at random. In that exercise, the drawing changed every time the system called paintComponent to redraw the panel. To create a more consistent drawing that remains the same each time it is drawn, we must store information about the displayed shapes so that we can reproduce them exactly each time the system calls

paintComponent.

[Page 398]

To do this, we will create a set of shape classes that store information about each shape. We will make these classes "smart" by allowing objects of these classes to draw themselves if provided with a Graphics object. Figure 8.21 declares class MyLine, which has all these capabilities.

Figure 8.21. MyLine class represents a line.

1// Fig. 8.21: MyLine.java

2// Declaration of class MyLine.

3import java.awt.Color;

4import java.awt.Graphics;

5

6public class MyLine

7{

8 private int x1; // x coordinate of first endpoint

9private int y1; // y coordinate of first endpoint

10private int x2; // x coordinate of second endpoint

11private int y2; // y coordinate of second endpoint

12private Color myColor; // color of this shape

13

14 // constructor with input values

15 public MyLine( int x1, int y1, int x2, int y2, Color color )

16{

17this.x1 = x1; // set x coordinate of first endpoint

18this.y1 = y1; // set y coordinate of first endpoint

19this.x2 = x2; // set x coordinate of second endpoint

20this.y2 = y2; // set y coordinate of second endpoint

21myColor = color; // set the color

22} // end MyLine constructor

23

24// Draw the line in the specified color

25public void draw( Graphics g )

26{

27g.setColor( myColor );

28g.drawLine( x1, y1, x2, y2 );

29} // end method draw

30} // end class MyLine

Class MyLine imports Color and Graphics (lines 34). Lines 811 declare instance variables for the coordinates needed to draw a line, and line 12 declares the instance variable that stores the color of the line. The constructor at lines 1522 takes five parameters, one for each instance variable that it initializes. Method draw at lines 2529 requires a Graphics object and uses it to draw the line in the proper color and at the proper coordinates.

In Fig. 8.22, we declare class DrawPanel, which will generate random objects of class MyLine. Line 12 declares a MyLine array to store the lines to draw. Inside the constructor (lines 1537), line 17 sets the

background color to Color.WHITE. Line 19 creates the array with a random length between 5 and 9. The loop at lines 2236 creates a new MyLine for every element in the array. Lines 2528 generate random coordinates for each line's endpoints, and lines 3132 generate a random color for the line. Line 35 creates a new MyLine object with the randomly generated values and stores it in the array.

[Page 399]

Figure 8.22. Creating random MyLine objects.

1 // Fig. 8.22: DrawPanel.java

2 // Program that uses class MyLine

3// to draw random lines.

4import java.awt.Color;

5import java.awt.Graphics;

6import java.util.Random;

7import javax.swing.JPanel;

9public class DrawPanel extends JPanel

10{

11private Random randomNumbers = new Random();

12private MyLine lines[]; // array of lines

13

14 // constructor, creates a panel with random shapes

15public DrawPanel()

16{

17setBackground( Color.WHITE );

19lines = new MyLine[ 5 + randomNumbers.nextInt( 5 ) ];

21// create lines

22 for ( int count = 0; count < lines.length; count++ )

23{

24// generate random coordinates

25int x1 = randomNumbers.nextInt( 300 );

26int y1 = randomNumbers.nextInt( 300 );

27int x2 = randomNumbers.nextInt( 300 );

28int y2 = randomNumbers.nextInt( 300 );

30// generate a random color

31Color color = new Color( randomNumbers.nextInt( 256 ),

32

randomNumbers.nextInt( 256

),

randomNumbers.nextInt( 256 ) );

33

 

 

 

 

 

 

34

// add

the line to the list of lines

to

be displayed

35

lines[

count ] = new MyLine(

x1,

y1,

x2,

y2, color );

36} // end for

37} // end DrawPanel constructor

39// for each shape array, draw the individual shapes

40public void paintComponent( Graphics g )

41{

42super.paintComponent( g );

44// draw the lines

45for ( MyLine line : lines )

46line.draw( g );

47} // end method paintComponent

48} // end class DrawPanel

Method paintComponent iterates through the MyLine objects in array lines using an enhanced for statement (lines 4546). Each iteration calls the draw method of the current MyLine object and passes it the Graphics object for drawing on the panel. Class TestDraw in Fig. 8.23 sets up a new window to display our drawing. Since we are setting the coordinates for the lines only once in the constructor, the drawing does not change if paint-Component is called to refresh the drawing on the screen.

[Page 400]

Figure 8.23. Creating JFrame to display DrawPanel.

1

//

Fig. 8.23: TestDraw

.java

2

//

Test application to

display a DrawPanel.

3

import javax.swing.JFrame;

4

 

 

 

5public class TestDraw

6{

7public static void main( String args[] )

8{

9DrawPanel panel = new DrawPanel();

10JFrame application = new JFrame();

12application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

13application.add( panel );

14application.setSize( 300, 300 );

15application.setVisible( true );

16} // end main

17} // end class TestDraw

GUI and Graphics Case Study Exercise

8.1Extend the program in Fig. 8.21Fig. 8.23 to randomly draw rectangles and ovals. Create classes MyRectangle and MyOval. Both of these classes should include x1, y1, x2, y2 coordinates, a color and a boolean flag to determine whether the shape is a filled shape. Declare a constructor in each class with arguments for initializing all the instance variables. To help draw rectangles and ovals, each class should provide methods getUpperLeftX, getUpperLeftY, getWidth and getHeight that calculate the upper-left x-coordinate, upper-left y-coordinate, width and height, respectively. The upper-left x-coordinate is the smaller of the two x-coordinate values, the upper-left y- coordinate is the smaller of the two y-coordinate values, the width is the absolute value of the difference between the two x-coordinate values, and the height is the absolute value of the difference between the two y-coordinate values.

[Page 401]

Class DrawPanel, which extends JPanel and handles the creation of the shapes, should declare three arrays, one for each shape type. The length of each array should be a random number between 1 and 5. The constructor of class DrawPanel will fill each of the arrays with shapes of random position, size, color and fill.

In addition, modify all three shape classes to include the following:

a.A constructor with no arguments that sets all the coordinates of the shape to 0, the color of the shape to Color.BLACK, and the filled property to false

(MyRect and MyOval only).

b.Set methods for the instance variables in each class. The methods that set a coordinate value should verify that the argument is greater than or equal to zero before setting the coordinateif it is not, they should set the coordinate to zero. The constructor should call the set methods rather than initialize the local variables directly.

c.Get methods for the instance variables in each class. Method draw should reference the coordinates by the get methods rather than access them directly.

[Page 401 (continued)]

8.19. (Optional) Software Engineering Case Study: Starting to Program the Classes of the ATM System

In the "Software Engineering Case Study" sections in Chapters 17, we introduced the fundamentals of object orientation and developed an object-oriented design for our ATM system. Earlier in this chapter, we discussed many of the details of programming with Java classes. We now begin implementing our object-oriented design in Java. At the end of this section, we show how to convert class diagrams to Java code. In the final "Software Engineering Case Study" section (Section 10.9), we modify the code to incorporate the object-oriented concept of inheritance. We present the full Java code implementation in Appendix J.

Visibility

We now apply access modifiers to the members of our classes. In Chapter 3, we introduced access modifiers public and private. Access modifiers determine the visibility or accessibility of an object's attributes and methods to other objects. Before we can begin implementing our design, we must consider which attributes and methods of our classes should be public and which should be private.

In Chapter 3, we observed that attributes normally should be private and that methods invoked by clients of a given class should be public. Methods that are called only by other methods of the class as "utility methods," however, normally should be private. The UML employs visibility markers for modeling the visibility of attributes and operations. Public visibility is indicated by placing a plus sign (+) before an operation or an attribute, whereas a minus sign () indicates private visibility. Figure 8.24 shows our updated class diagram with visibility markers included. [Note: We do not include any operation parameters in Fig. 8.24this is perfectly normal. Adding visibility markers does not affect the parameters already modeled in the class diagrams of Fig. 6.22Fig. 6.25.]

Figure 8.24. Class diagram with visibility markers.

(This item is displayed on page 402 in the print version)

[View full size image]

Navigability

Before we begin implementing our design in Java, we introduce an additional UML notation. The class diagram in Fig. 8.25 further refines the relationships among classes in the ATM system by adding navigability arrows to the association lines. Navigability arrows (represented as arrows with stick arrowheads in the class diagram) indicate in which direction an association can be traversed. When implementing a system designed using the UML, programmers use navigability arrows to help determine which objects need references to other objects. For example, the navigability arrow pointing from class ATM to class BankDatabase indicates that we can navigate from the former to the latter, thereby enabling the ATM to invoke the BankDatabase's operations. However, since Fig. 8.25 does not contain a navigability arrow pointing from class BankDatabase to class ATM, the BankDatabase cannot access the ATM's operations. Note that associations in a class diagram that have navigability arrows at both ends or do not have navigability arrows at all indicate bidirectional navigabilitynavigation can proceed in either direction across the association.

[Page 402]

Figure 8.25. Class diagram with navigability arrows.

(This item is displayed on page 403 in the print version)

[View full size image]

Like the class diagram of Fig. 3.24, the class diagram of Fig. 8.25 omits classes BalanceInquiry and Deposit to keep the diagram simple. The navigability of the associations in which these classes participate closely parallels the navigability of class Withdrawal. Recall from Section 3.10 that BalanceInquiry has an association with class Screen. We can navigate from class BalanceInquiry to class Screen along this association, but we cannot navigate from class Screen to class BalanceInquiry. Thus, if we were to model class BalanceInquiry in Fig. 8.25, we would place a navigability arrow at class Screen's end of this association. Also recall that class Deposit associates with classes Screen, Keypad and DepositSlot. We can navigate from class Deposit to each of these classes, but not vice versa. We therefore would place navigability arrows at the Screen, Keypad and DepositSlot ends of these associations. [Note: We model these additional classes and associations in our final class diagram in Section 10.9, after we have simplified the structure of our system by incorporating the object-oriented concept of inheritance.]

[Page 403]

Implementing the ATM System from Its UML Design

We are now ready to begin implementing the ATM system. We first convert the classes in the diagrams of Fig. 8.24 and Fig. 8.25 into Java code. The code will represent the "skeleton" of the system. In Chapter 10, we modify the code to incorporate the object-oriented concept of inheritance. In Appendix J, ATM Case Study Code, we present the complete working Java code for our model.

As an example, we develop the code from our design of class Withdrawal in Fig. 8.24. We use this figure to determine the attributes and operations of the class. We use the UML model in Fig. 8.25 to determine the associations among classes. We follow the following four guidelines for each class:

1.Use the name located in the first compartment to declare the class as a public class with an empty no-argument constructor. We include this constructor simply as a placeholder to remind us that most classes will indeed need constructors. In Appendix J, when we complete a working version of this class, we add any necessary arguments and code the body of the constructor as needed. For example, class Withdrawal yields the code in Fig. 8.26. [Note: If we find that the

class's instance variables require only default initialization, then we remove the empty noargument constructor because it is unnecessary.]

[Page 404]

Figure 8.26. Java code for class Withdrawal based on Fig. 8.24 and Fig. 8.25.

1 // Class Withdrawal represents an ATM withdrawal transaction

2public class Withdrawal

3{

4// no-argument constructor

5public Withdrawal()

6{

7} // end no-argument Withdrawal constructor

8} // end class Withdrawal

2.Use the attributes located in the second compartment to declare the instance variables. For example, the private attributes accountNumber and amount of class Withdrawal yield the code in Fig. 8.27. [Note: The constructor of the complete working version of this class will assign values to these attributes.]

Figure 8.27. Java code for class Withdrawal based on Fig. 8.24 and Fig. 8.25.

1 // Class Withdrawal represents an ATM withdrawal transaction

2public class Withdrawal

3{

4// attributes

5

private

int accountNumber; // account to withdraw funds from

6

private

double amount; // amount to withdraw

7

 

 

8// no-argument constructor

9public Withdrawal()

10{

11} // end no-argument Withdrawal constructor

12} // end class Withdrawal

3.Use the associations described in the class diagram to declare the references to other objects. For example, according to Fig. 8.25, Withdrawal can access one object of class Screen, one object of class Keypad, one object of class CashDispenser and one object of class BankDatabase. This yields the code in Fig. 8.28. [Note: The constructor of the complete working version of this class will initialize these instance variables with references to actual objects.]

Figure 8.28. Java code for class Withdrawal based on Fig. 8.24 and Fig. 8.25.

(This item is displayed on page 405 in the print version)

1 // Class Withdrawal represents an ATM withdrawal transaction

2public class Withdrawal

3{

4// attributes

5

private

int accountNumber; // account to withdraw funds from

6

private

double amount; // amount to withdraw

7

 

 

8// references to associated objects

9private Screen screen; // ATM's screen

10private Keypad keypad; // ATM's keypad

11private CashDispenser cashDispenser; // ATM's cash dispenser

12private BankDatabase bankDatabase; // account info database

14// no-argument constructor

15public Withdrawal()

16{

17} // end no-argument Withdrawal constructor

18} // end class Withdrawal

4.Use the operations located in the third compartment of Fig. 8.24 to declare the shells of the methods. If we have not yet specified a return type for an operation, we declare the method with return type void. Refer to the class diagrams of Fig. 6.22Fig. 6.25 to declare any necessary parameters. For example, adding the public operation execute in class Withdrawal, which has an empty parameter list, yields the code in Fig. 8.29. [Note: We code the bodies of methods when we implement the complete system in Appendix J.]

Figure 8.29. Java code for class Withdrawal based on Fig. 8.24 and Fig. 8.25.

(This item is displayed on page 405 in the print version)

1 // Class Withdrawal represents an ATM withdrawal transaction

2public class Withdrawal

3{

4// attributes

5

private

int accountNumber; // account to withdraw funds from

6

private

double amount; // amount to withdraw

7

 

 

8// references to associated objects

9private Screen screen; // ATM's screen

10private Keypad keypad; // ATM's keypad

11private CashDispenser cashDispenser; // ATM's cash dispenser

12private BankDatabase bankDatabase; // account info database

14// no-argument constructor

15public Withdrawal()

16{

17} // end no-argument Withdrawal constructor

19// operations

20public void execute()

21{

22} // end method execute

23} // end class Withdrawal

This concludes our discussion of the basics of generating classes from UML diagrams.

[Page 405]

Software Engineering Case Study Self-Review Exercises

8.1 State whether the following statement is true or false, and if false, explain why: If an attribute of a class is marked with a minus sign (-) in a class diagram, the attribute is not directly accessible outside of the class.

[Page 406]