• No results found

PUTTING ALL PIECES TOGETHER

In document Java Programming Fundamentals (Page 119-142)

We are now ready to put all the pieces of a class together. Th ere is no specifi c order for methods or instance variables. However, throughout this book the following order is maintained:

1. Instance variables 2. Constructors

3. Application specifi c methods

4. Accessor methods returning the instance variable value 5. Mutator methods modifying the instance variable 6. toString method

Once again, we stress that this order is purely the author’s choice and you need not fol-low this. Th e Stock class we developed is presented in Example 3.7.

Example 3.7 /**

Keeps ticker symbol, number of shares and dividend information.

*/

class Stock {

private int numberOfShares;

private String tickerSymbol;

private double dividend;

/**

Constructs a Stock with zero shares */

public Stock() {

numberOfShares = 0;

tickerSymbol = "[NA]";

dividend = 0.0;

} /**

Computes and returns yearly dividend @return the yearly dividend

*/

Apago PDF Enhancer

public double yearlyDividend() {

double totalDividend;

totalDividend = numberOfShares * dividend;

return totalDividend;

} /**

Accessor method for the number of shares @return the number of shares

*/

public int getNumberOfShares() {

return numberOfShares;

} /**

Accessor method for the ticker symbol @return the ticker symbol

*/

public String getTickerSymbol() {

return tickerSymbol;

} /**

Accessor method for the dividend @return the dividend

*/

public double getDividend() {

return dividend;

} /**

Mutator method to set the number of shares

@param inNumberOfShares new value for the number

of shares

*/

public void setNumberOfShares(int inNumberOfShares) {

numberOfShares = inNumberOfShares;

}

Apago PDF Enhancer

/**

Mutator method to set the ticker symbol

@param inTickerSymbol new value for the ticker

symbol

*/

public void setTickerSymbol(String inTickerSymbol) {

tickerSymbol = inTickerSymbol;

}

/**

Mutator method to set the dividend

@param inDividend new value for the dividend */

public void setDividend(double inDividend) {

dividend = inDividend;

}

/**

The toString method

@return number of shares and ticker symbol */

public String toString() {

String str;

str = numberOfShares + " " + tickerSymbol;

return str;

} }

Advanced Topic 3.1: Representing Class in UML 2

As mentioned in Chapter 1, the unifi ed modeling language (UML) is a standard language for soft ware specifi cation. Th e UML uses mostly graphical notations to express the design of soft ware projects. Th e unifi ed modeling language version 2 (UML 2) is the latest version of UML. Th e UML 2 notation of the Stock class is shown in Figure 3.2.

Th ere are three distinct areas: class name area, instance variable area, and operations area. Th e − sign and + sign indicate the access modifi ers private and public, respec-tively. A simplifi ed notation for the Stock class in UML 2 notation is shown in Figure 3.3 and it is quite useful in showing relationships among classes.

Apago PDF Enhancer

TESTING

Every class you create must be tested thoroughly before it is used in any application. Th e most general approach to test a class is to create an application program and test every method of the class you have developed. Th is approach is followed in this book and is illustrated in the next example. Java development environments such as BlueJ provide the facility to test a class without an application program. Th e readers are encouraged to test their class by creating an application program.

Example 3.8

In this example we create an application to test the Stock class.

As you know by now, every application has at least one class and one of the classes of the application has a method main. Th erefore, we create an application having exactly one class that contains the method main as shown below:

public class StockTesting {

public static void main (String[] args) {

//Java statements to test Stock class }

}

Stock

+yearlyDividend() : double +getNumberOfShares() : int +getTickerSymbol() : String +getDividend() : double +setNumberOfShares(int) : void +setTickerSymbol(String) : void +setDividend(double) : void +toString():void

-numberOfShares : int -tickerSymbol : String -dividend : double

FIGURE 3.2 Class diagram of Stock class.

Stock

FIGURE 3.3 Simplifi ed class diagram of Stock class.

Apago PDF Enhancer

To begin with, to test any method of the Stock class, you must create an instance of the Stock class. Th e required Java statement is

Stock testStock = new Stock(); //(1)

Th e left -hand side of the above assignment statement declares a reference variable testStock of the type Stock. Th e right-hand side creates a new object belonging to the Stock class and returns the reference. In fact the new on the right-hand side is an operator that creates an instance of the class on the basis of the constructor that follows. For example, Stock() is a constructor with no formal parameter.

Such a constructor is known as default constructor and is present in every class by default so long as there is no user-defi ned constructor. A default constructor initial-izes every instance variable of the object with default values. In this example, we have already included a constructor with no formal parameter, and therefore the right-hand side of Statement 1 creates an instance of the Stock class, initializes numberOfShares to 0, tickerSymbol to "[NA]", and dividend to 0.0.

Th e new operator returns the reference of the object created. Th us, the variable testStock has the reference of the new object created. Note that Statement 1 is equivalent to the following two statements:

Stock testStock; //(2) testStock = new Stock(); //(3)

Statement 2 declares a local variable testStock. Statement 3 creates a new instance of Stock and initializes the reference variable testStock with the ref-erence of the newly created instance returned by the new operator. In other words, Statement 3 instantiates the local variable testStock.

Now to test a pair of accessor and mutator methods corresponding to an instance variable, the best way is to get an input value, use the mutator method to store it, and then output it with the help of corresponding accessor method. Once all instance variables received valid data values, application specifi c methods and toString method can be tested. Th us, we have the following Java application program:

import java.util.Scanner;

/**

An application class to test Stock class

*/

public class StockTesting {

public static void main (String[] args)

Apago PDF Enhancer

{

//Create an object belonging to the class Stock Stock testStock = new Stock();

//Declare local variables

int inputNumberOfShares, outputNumberOfShares;

String inputTickerSymbol, outputTickerSymbol;

double inputDividend, outputDividend;

double outputYearlyDividend;

//Get input values

Scanner scannedInfo = new Scanner(System.in);

System.out.print("Enter numbers own, stock symbol"

+ " and dividend : ");

System.out.flush();

inputNumberOfShares = scannedInfo.nextInt();

inputTickerSymbol = scannedInfo.next();

inputDividend = scannedInfo.nextDouble();

System.out.println();

//Test mutator and accessor methods

testStock.setNumberOfShares(inputNumberOfShares);

testStock.setTickerSymbol(inputTickerSymbol);

testStock.setDividend(inputDividend);

outputNumberOfShares

= testStock.getNumberOfShares ();

outputTickerSymbol = testStock.getTickerSymbol();

outputDividend = testStock.getDividend();

System.out.println("Number of shares : " +

outputNumberOfShares);

System.out.println("Stock symbol is : " +

outputTickerSymbol);

System.out.println("Dividend per share is : " + outputDividend);

//Test yearlyDividend method

outputYearlyDividend = testStock.yearlyDividend();

System.out.println("Yearly Dividend is : " +

outputYearlyDividend);

//Test toString method

Apago PDF Enhancer

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

} }

Output

Enter numbers own, stock symbol and dividend: 500 XYZ 1.43 Number of shares : 500

Stock symbol : XYZ

Dividend per share : 1.43 Yearly Dividend : 715.0 500 XYZ

Self-Check 29. True or false: Every class needs to be tested.

30. Testing will help identify errors.

Advanced Topic 3.2: Representing Relationship in UML 2

Th e UML 2 class diagram of StockTesting application is presented in Figure 3.4. Th e association is the most common relationship that exists among classes and it represents the relationship among instances of classes. Th e multiplicity of the association denotes

Stock

+yearlyDividend() : double +getNumberOfShares() : int +getTickerSymbol() : String +getDividend() : double +setNumberOfShares(int) : void +setTickerSymbol(String) : void +setDividend(double) : void +toString():void

-numberOfShares : int -tickerSymbol : String -dividend : double StockTesting

+main(String[]) : void 1 uses

1..*

FIGURE 3.4 Class diagram of StockTesting application.

Apago PDF Enhancer

the number of objects participating in such a relationship. For example, an instance of the class StockTesting uses one or more instances of the class Stock. Th us, there is an association between class StockTesting and class Stock. Th e number 1 appearing near the class StockTesting indicates that corresponding to one Stock object there is 1 StockTesting object and the notation 1..* appearing near the class Stock indicates that corresponding to one StockTesting object there can be 1 to many Stock objects.

Both 1 and 1..* are known as the multiplicity.

Advanced Topic 3.3: Class Design, Implementation, and Testing

In this section, we continue with the soft ware development process outlined in Chapter 1.

As mentioned in Chapter 1, design, implementation, and testing phases are covered in this section. We list them fi rst for easy reference and then proceed to elaborate on each of those phases through an example.

Phase 2. Design

Step 1. Decide on attributes Step 2. Decide on methods

Phase 3. Implementation (or create classes using Java constructs) Phase 4. Testing

Design

Th e primary aim of this phase is to decide on various classes required and assign respon-sibilities to each one of them. Design of the soft ware begins with a formal specifi cation of the intended product. Th e following is an example of a formal specifi cation of a circular counter.

Example 3.9

A circular counter counts 0, 1, 2, …, limit − 1. Once the counter reaches limit − 1, the next value is not limit, rather it is 0. In other words, a circular counter can count up to limit − 1 and then it resets to 0. Th e value of the limit can be any integer greater than 1.

From the above specifi cation, it is quite clear that the soft ware we develop must provide a “get counter value” service to the user. Without such a service, the counter is of no use. Being a counter, there needs to be service to “increment the counter value.” Another useful service is “set counter value.” Being a circular counter, there is a limit value and there needs to be services to set and get the limit value. On the basis of this analysis, we can create the use case diagram given in Figure 3.5.

Th e design phase starts where the use case analysis left off . Th us in this example, from the use case diagram given in Figure 3.5, we tentatively decide to have one class named CircularCounter.

Apago PDF Enhancer

Decide on Attributes

From the use case diagram, it is quite clear that the circular counter must keep the current value of the counter and limit value. Clearly, both of these values can be of int data type.

Th erefore, the CircularCounter class needs the following two attributes:

private int counterValue;

private int limitValue;

Decide on Methods

In this step you need to decide on methods. As explained before, you may include accessor and mutator methods corresponding to each instance variable. You may also provide a toString method. So in this section the focus is on additional methods that are needed for this class to meet its specifi cations.

Th e “increment counter” is the only use case that needs to be addressed. Th erefore, there must be a method to increment the counter value by one. In this case, you must clearly state preconditions and postconditions. Preconditions refer to the necessary condi-tions for the method to behave as specifi ed. Postcondicondi-tions refer to the condicondi-tions satisfi ed by inst ance variables at the completion of the method invocation. Th e set of values of all instance variables is called the state of an object. Th us, preconditions and postconditions specify the states of an object before and aft er a method have been invoked. In this case, the

Circular counter

Set counter

User

Get counter

Increment counter

Set limit value

Get limit value

FIGURE 3.5 Use case diagram for the circular counter.

Apago PDF Enhancer

preconditions are limitValue > 0 and 0 ≤ counterValue < limitValue. Th e post-conditions are limitValue > 0, 0 ≤ counterValue < limitValue and counter-Value is incremented by 1 in the circular order 0, 1, 2, ..., limitValue - 1, 0.

Th us, the class has the following six methods:

public void incrementCounterValue() // Preconditions : limitValue > 0;

// 0 ≤ counterValue < limitValue.

// Postconditions : limitValue > 0;

// 0 ≤ counterValue < limitValue;

// counterValue is incremented by 1

// in the circular order

// 0, 1, 2, ..., limitValue - 1, 0.

public int getCounterValue() public int getLimitValue()

public void setCounterValue(int inCounterValue) public void setLimitValue(int inLimitValue) public void toString()

Consider the following expression:

(counterValue + 1) % limitValue

Assume that limitValueis 5. Now counterValuehas to be one of the following: 0, 1, 2, 3, and 4. Let us evaluate the above expression for each of those values (see Table 3.2).

Th us, the above expression computes the next value based on counterValue as desired. Th erefore, the Java statement

counterValue = (counterValue + 1) % limitValue

increments instance variable counterValue in circular order 0, 1, 2, ..., limitValue - 1,0.

Th e circular counter can be visualized as in Figure 3.6 and the class diagram is given in Figure 3.7.

TABLE 3.2 Illustration of Circular Increment

counterValue (counterValue +1) % limitValue

0 (0 + 1) % 5 = 1 % 5 = 1

1 (1 + 1) % 5 = 2 % 5 = 2

2 (2 + 1) % 5 = 3 % 5 = 3

3 (3 + 1) % 5 = 4 % 5 = 4

4 (4 + 1) % 5 = 5 % 5 = 0

Apago PDF Enhancer

Implementation

In this phase, we use Java programming language to code the class(es) designed in the design phase.

/**

Circular counter counts 0, ..., limit - 1, 0

*/

public class CircularCounter {

private int counterValue;

private int limitValue;

/**

Constructs a circular counter limitValue 100;

counterValue 0.

*/

public CircularCounter() {

counterValue = 0;

CircularCounter

− counterValue : int

− limitValue : int

+incrementCounterValue() : void +getCounterValue() : int +getLimitValue() : int +setCounterValue(int) : void +setLimitValue(int) : void +toString() : String

FIGURE 3.7 Class diagram of CircularCounter class.

CircularCounter

counterValue

limitValue

FIGURE 3.6 Visualization of CircularCounter.

Apago PDF Enhancer

limitValue = 100;

} /**

Increments the circular counter */

public void incrementCounterValue() {

counterValue = (counterValue + 1) % limitValue;

} /**

Accessor method for the counter value @return the counter value

*/

public int getCounterValue() {

return counterValue;

} /**

Accessor method for the limit value @return the limit value

*/

public int getLimitValue() {

return limitValue;

} /**

Mutator method to set the counter value

@param inCounterValue new value for the counter value */

public void setCounterValue(int inCounterValue) {

counterValue = inCounterValue % limitValue;

} /**

Mutator method to set the limit value

@param inLimitValue new value for the limit value */

public void setLimitValue(int inLimitValue)

Apago PDF Enhancer

{

limitValue = inLimitValue;

} /**

The toString method

@return counter value and limit information */

public String toString() {

String str;

str = "Counter (0 to " + (limitValue - 1) + ") value : "

+ counterValue;

return str;

} } Testing

In this phase we create an application program to test the class CircularCounter. Th e UML 2 diagram is shown in Figure 3.8 and the code is as follows:

import java.util.Scanner;

/**

The application tester class for circular counter

*/

public class CircularCounterTesting {

public static void main (String[] args) {

//Create an instance of CircularCounter CircularCounter testCir cularCounter = new

CircularCounter();

//Declare variables to input and output counterValue // and limitValue

int inputCounterValue, outputCounterValue;

int inputLimitValue, outputLimitValue;

int outputIncrementCounterValue;

//Get two input values

Scanner scannedInfo = new Scanner(System.in);

Apago PDF Enhancer

System.out.print("Enter counter value and limit value : ");

System.out.flush();

inputCounterValue = scannedInfo.nextInt();

inputLimitValue = scannedInfo.nextInt();

System.out.println();

//Test mutator and accessor corresponding //to instance variables.

testCircularCounter.setCounterValue(inputCounterValue);

testCircularCounter.setLimitValue(inputLimitValue);

outputCounterValue =

testCircularCounter.getCounterValue();

outputLimitValue =

testCircularCounter.getLimitValue();

System.out.println("Counter value : "+

outputCounterValue);

System.out.println("Limit value : "+

outputLimitValue);

//Test incrementCounterValue method

System.out.println("Counter is incremented

five times ");

System.out.println(testCircularCounter);

testCircularCounter.incrementCounterValue();

System.out.println(testCircularCounter);

testCircularCounter.incrementCounterValue();

System.out.println(testCircularCounter);

testCircularCounter.incrementCounterValue();

System.out.println(testCircularCounter);

testCircularCounter.incrementCounterValue();

System.out.println(testCircularCounter);

testCircularCounter.incrementCounterValue();

System.out.println(testCircularCounter);

} }

Output

Enter counter value and limit value : 3 5 Counter value : 3

Limit value : 5

Apago PDF Enhancer

FIGURE 3.8 Class diagram of circular testing program.

+main(String[]) : void

1 uses

1..*

CircularCounter

+incrementCounterValue() : void +getCounterValue() : int +getLimitValue() : int +setCounterValue(int) : void +setLimitValue(int) : void +toString() : String

− counterValue : int

− limitValue : int CircularCounterTesting

Counter is incremented five times Counter (0 to 4) value : 3

Counter (0 to 4) value : 4 Counter (0 to 4) value : 0 Counter (0 to 4) value : 1 Counter (0 to 4) value : 2 Counter (0 to 4) value : 3

Note 3.1 Compare Figures 3.4 and 3.8. Observe that the essential diff erence is that in Fig-ure 3.4 we have the Stock class and in FigFig-ure 3.8 we have CircularCounter class. In other words, once the UML 2 class diagram for a class is created, the UML 2 class diagram for the corresponding testing program is quite obvious. Th erefore, we omit such fi gures.

REVIEW

1. A class has attributes and operations: attributes are used to store the data, and opera-tions access and manipulate the data values.

2. Keeping data along with operations is known as encapsulation.

3. Unless there is a very compelling reason, all attributes are declared as private.

4. A private attribute (or operation) is accessible only to the object.

Apago PDF Enhancer

5. A public attribute (or operation) is accessible to any object.

6. Operations of a class are generally declared as public.

7. Implementation of an operation is called a method.

8. Operations provide the necessary interface to initialize or modify an attribute, retrieve the current value of an attribute, and compute a new value based on current value of attributes.

9. A Java program is a collection of collaborating objects.

10. Th e syntax for invoking a method using a reference variable is referenceVariableName.methodName();

Th e reference variable is called an explicit parameter.

11. Th ere are two types of methods: value returning methods and void methods.

12. A void method cannot be invoked in an expression. It is invoked as a stand-alone Java statement.

13. A value returning method can be invoked in an assignment statement or can be used in an expression or as part of an output statement. If the value returned is not stored using an assignment statement, it will be lost forever.

14. A method has two parts: the header

public static void main (String[] args) and the body

{

[statements]

}

15. Th e header ends with a list of formal parameters (or arguments) enclosed within a pair of parentheses. Th e list of formal parameters in a method header can be empty. How-ever, the pair of parentheses enclosing the formal parameter cannot be omitted.

16. As part of the method invocation, the actual parameter value is copied into the for-mal parameter.

17. Inside a method, you can declare additional variables. All variables declared inside a method, excluding the formal parameters in the header, are known as local variables.

18. A local variable is not accessible outside the block. Th erefore, no access modifi er is required.

Apago PDF Enhancer

19. An instance variable is available only within the object (if it is declared private).

A local variable is available only within the block from its point of declaration.

A formal parameter is available within the method.

20. An instance variable exists as long as the associated object exists. A local variable is created every time declaration statement is executed during the method execution and the variable ceases to exist upon the completion of the block. A formal parameter is created at the beginning of the method invocation and it ceases to exist upon the completion of the method.

21. At the beginning of the method invocation, the actual parameter value is copied to the formal parameter.

22. Once the return statement is executed, the control goes back to the Java statement that invoked the method.

23. A method that does not modify any instance variable of an object is called an acces-sor method. All other methods are known as mutator methods.

EXERCISES

1. Mark the following statements as true or false:

a. An accessor method can access only one attribute.

b. Th ere are two types of methods: value returning and void.

c. A mutator method modifi es at least one attribute.

d. A local variable can be made accessible outside the method by declaring it as public.

e. It is okay for a void method to return 0.

f. Every value returning method must have a return statement.

g. Every class must have a toString method.

h. Th e default constructor has no formal parameters.

i. A void method cannot be used on the right-hand side of an assignment statement.

j. Th e method main need not be a static method.

k. Th e method charAt of the String class is of type char.

l. Every method must have a return statement.

2. Mark the following method invocation as valid or invalid. If invalid, explain why it is invalid. Assume that scannedInfo is a reference variable of type Scanner, word is a reference variable of the type String, that references the String “Okay, Ready to go!” and stk is a reference variable of the type Stock.

2. Mark the following method invocation as valid or invalid. If invalid, explain why it is invalid. Assume that scannedInfo is a reference variable of type Scanner, word is a reference variable of the type String, that references the String “Okay, Ready to go!” and stk is a reference variable of the type Stock.

In document Java Programming Fundamentals (Page 119-142)