Transcript Slide 1

Chapter 8 – Designing Classes
Copyright © 2014 by John Wiley & Sons. All rights reserved.
1
Chapter Goals
 To learn how to choose appropriate classes for a given
problem
 To understand the concept of cohesion
 To minimize dependencies and side effects
 To learn how to find a data representation for a class
 To understand static methods and variables
 To learn about packages
Copyright © 2014 by John Wiley & Sons. All rights reserved.
2
Discovering Classes
 A class represents a single concept from the problem
domain.
 Name for a class should be a noun that describes
concept.
• Concepts from mathematics:
Point
Rectangle
Ellipse
• Concepts from real life:
BankAccount
CashRegister
Copyright © 2014 by John Wiley & Sons. All rights reserved.
3
Discovering Classes
 Actors
• objects do some kinds of work for you:
Scanner
Random // Better name: RandomNumberGenerator
 Utility classes
• no objects, only static methods and constants:
Math
 Program starters:
• a class with only a main method
Copyright © 2014 by John Wiley & Sons. All rights reserved.
4
Naming Classes
 The class name should indicate what objects of
the class will do:
• Paycheck is a better name than PaycheckProgram.
 Don't turn a single operation action into a class:
• Paycheck is a better name than ComputePaycheck.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
5
Question
What is the rule of thumb for finding classes?
Answer: Look for nouns in the problem description.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
6
Designing Good Methods - Cohesion
 A class should represent a single concept.
 The public interface of a class is cohesive if all of its
features are related to the concept that the class
represents.
 The members of a cohesive team have a common goal.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
7
Designing Good Methods - Cohesion
 This class lacks cohesion.
public class CashRegister
{
public static final double QUARTER_VALUE = 0.25;
public static final double DIME_VALUE = 0.1;
public static final double NICKEL_VALUE = 0.05;
. . .
public void receivePayment(int dollars,
int quarters, int dimes, int nickels,
int pennies)
. . .
}
 It contains two concepts:
• A cash register that holds coins and computes their total
• The values of individual coins.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
8
Designing Good Methods - Cohesion
 Solution: Make two classes:
public class Coin
{
double value;
String type;
}
public Coin(double aValue, String aName) { . . . }
public double getValue() { . . . }
. . .
public class CashRegister
{
. . .
public void receivePayment(int coinCount, Coin coinType)
{
payment = payment + coinCount * coinType.getValue();
}
. . .
}
 Now CashRegister class can handle any type of coin.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
9
Minimizing Dependencies
 A class depends on another class if its methods use that
class in any way.
• CashRegister depends on Coin
 UML: Unified Modeling Language
• Notation for object-oriented analysis and design
Copyright © 2014 by John Wiley & Sons. All rights reserved.
10
Minimizing Dependencies
Figure 1 UML class diagram showing dependency
relationship between the CashRegister and Coin
Classes.
 The Coin class does not depend on the CashRegister
class.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
11
Separating Accessors and Mutators
 A mutator method:
• changes the state of an object (i.e. modify value of instance
variables).
• E.g. withdraw method in BankAccount class
 An accessor method:
asks an object to compute a result
doesn’t change the state (i.e. only looks up value of instance
variable).
• E.g. getBalance method in BankAccount class
•
•
 An immutable class:
• Class with no mutator methods.
• E.g. String is an immutable class
• No method in the String class can modify the contents of a string.
• References to objects of an immutable class can be safely shared.
 A mutable class:
•
accessors + mutators
Copyright © 2014 by John Wiley & Sons. All rights reserved.
12
Separating Accessors and Mutators
 Mutator method:
•
•
•
•
Change the state of an object
Usually a method that does NOT return a value.
In general, SHOULD have return type void
Sometimes, can return an informational value.
• E.g. ArrayList remove method returns true if the removal was
successful.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
13
Minimizing Side Effects
 In general, a method should not modify its parameter
variables.
/** Computes the total balance of the given accounts.
@param accounts a list of bank accounts
*/
public double getTotalBalance(ArrayList<BankAccount> accounts)
{
double sum = 0;
while (accounts.size() > 0)
{
BankAccount account = accounts.remove(0); // Not recommended
sum = sum + account.getBalance();
}
return sum;
}
 Such a side effect would not be what most programmers
expect.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
14
Programming Question
 Add following method below main moethod of BankAccountTester class.
public double getTotalBalance(ArrayList<BankAccount> accounts)
{
double sum = 0;
while (accounts.size() > 0)
{
BankAccount account = accounts.remove(0); // Not recommended
sum = sum + account.getBalance();
}
return sum;
}
 Modify main method by creating array list accounts and adding 3 bank
account objects with balance $1000, $2000 and $3000 respectively.
Print the balances of each account object balance.
 Next call getTotalBalance method with accounts as argument
 Print balances of each account object in acconts arrayList again.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
15
Answer
BankAccountTester.java
import java.util.ArrayList;
public class BankAccountTester
{
public static void main(String args[])
{
ArrayList<BankAccount> accounts = new ArrayList<BankAccount>();
BankAccount acct1 = new BankAccount(1000.00);
accounts.add(acct1);
BankAccount acct2 = new BankAccount(2000.00);
accounts.add(acct2);
BankAccount acct3 = new BankAccount(3000.00);
accounts.add(acct3);
for(BankAccount acct: accounts)
System.out.print("BankAccount balance before:"+ acct.getBalance());
System.out.println();
getTotalBalance(accounts);
for(BankAccount acct: accounts)
System.out.print("BankAccount balance after:"+ acct.getBalance());
System.out.println();
}
public static double getTotalBalance(ArrayList<BankAccount> accounts)
{
double sum = 0;
while (accounts.size() > 0)
{
BankAccount account = accounts.remove(0); // Not recommended
sum = sum + account.getBalance();
}
return sum;
}
}
Copyright © 2014 by John Wiley & Sons. All rights reserved.
16
 Output:
Copyright © 2014 by John Wiley & Sons. All rights reserved.
17
Minimizing Side Effects
 The following method mutates the System.out object,
which is not a part of the BankAccount object.
public void printBalance() // Not recommended
{
System.out.println("The balance is now $" +
balance);
}
 That is a side effect.
 Lesson learned:
• When designing methods, minimize side effects.
• Keep most of your classes free from input and output operations
Copyright © 2014 by John Wiley & Sons. All rights reserved.
18
Question
Is the Rectangle class immutable?
Copyright © 2014 by John Wiley & Sons. All rights reserved.
19
Answer
Is the Rectangle class immutable?
Answer: No – translate is a mutator.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
20
static Variables and Methods - Variables
 A static variable:
• Also called class variables
• Belongs to the class, not to any object of the class.
• E.g. To assign bank account numbers sequentially
• Have a single value of lastAssignedNumber that is a property of
the class, not any object of the class.
• Declare it using the static reserved word
public class BankAccount
{
private double balance;
private int accountNumber;
private static int lastAssignedNumber = 0;
public BankAccount(double balance)
{
this.balance = balance;
lastAssignedNumber++;
accountNumber = lastAssignedNumber;
}
. . .
}
Copyright © 2014 by John Wiley & Sons. All rights reserved.
21
Programming Question
 Modify BankAccount class to incorporate an
accountNumber variable (and lastAssignedNumber ).
Implement a toString method that returns a string with
the String representation of class(E.g. “Bank Account
No:1 balance:1000.0”).
 Modify BankAccountTester class to create multiple
bank accounts with different balances and print the
details of each bank account using toString method.
 A sample run is shown:
Copyright © 2014 by John Wiley & Sons. All rights reserved.
22
Answer
BankAccount.java
public class BankAccount
{
private double balance;
private int accountNumber;
private static int lastAssignedNumber = 0;
public BankAccount(double balance)
{
this.balance = balance;
lastAssignedNumber++;
accountNumber = lastAssignedNumber;
}
public String toString()
{
return "Bank Account No:"+accountNumber+"
balance:"+balance;
}
}
Copyright © 2014 by John Wiley & Sons. All rights reserved.
BankAccountTester.java
public class BankAccountTester
{
public static void main(String args[])
{
BankAccount acct1 = new
BankAccount(1000.00);
BankAccount acct2 = new
BankAccount(2000.00);
BankAccount acct3 = new
BankAccount(3000.00);
System.out.println(acct1);
System.out.println(acct2);
System.out.println(acct3);
}
}
23
static Variables and Methods
 Every BankAccount object has its own balance and
accountNumber instance variables
 All objects share a single copy of the
lastAssignedNumber variable (static/class variable)
• That variable is stored in a separate location, outside any
BankAccount objects
Copyright © 2014 by John Wiley & Sons. All rights reserved.
24
static Variables and Methods
Figure 5 A static Variable and Instance Variables
Copyright © 2014 by John Wiley & Sons. All rights reserved.
25
static Variables and Methods
 static variables:
• Should always be declared as private,
• This ensures that methods of other classes do not change their
values
 static constants:
• May be either private or public
public class BankAccount
{
public static final double OVERDRAFT_FEE = 29.95;
. . .
}
• Methods from any class can refer to the constant as
BankAccount.OVERDRAFT_FEE
Copyright © 2014 by John Wiley & Sons. All rights reserved.
26
static Variables and Methods - Methods
 Sometimes a class defines methods that are not invoked
on an object
• Called a static method
 Example: sqrt method of Math class
• a static method
• invoked as Math.sqrt(x)
• No object of the Math class is constructed.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
27
static Variables and Methods
 You can define your own static methods:
public class Financial
{
/** Computes a percentage of an amount.
@param percentage the percentage to apply
@param amount the amount to which the percentage is applied
@return the requested percentage of the amount
*/
public static double percentOf(double percentage, double amount)
{
return (percentage / 100) * amount;
}
}
Copyright © 2014 by John Wiley & Sons. All rights reserved.
28
static Variables and Methods
 When calling such a method, supply the name of the class
containing it:
double tax = Financial.percentOf(taxRate, total);
 The main method is always static.
• When the program starts, there aren’t any objects.
• Therefore, the first method of a program MUST be a static
method.
 Programming Tip:
• Minimize the Use of static Methods
Copyright © 2014 by John Wiley & Sons. All rights reserved.
29
Question
Name two static variables of the System class.
Answer: System.in and System.out.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
30
Question
Name a static constant of the Math class.
Answer: Math.PI
Copyright © 2014 by John Wiley & Sons. All rights reserved.
31
Question
The following method computes the average of an array of
numbers:
public static double average(double[] values)
Why should it not be defined as an instance method?
Answer: The method needs no data of any object. The
only required input is the values argument.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
32
Question
Harry tells you that he has found a great way to avoid those
pesky objects: Put all code into a single class and declare
all methods and variables static. Then main can call the
other static methods, and all of them can access the
static variables. Will Harry's plan work? Is it a good
idea?
Answer: Yes, it works. static methods can access
static variables of the same class. But it is a terrible
idea. As your programming tasks get more complex,
you will want to use objects and classes to organize
your programs.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
33
Packages
 Package: Set of related classes
 Important packages in the Java library:
/opt/java-jdk/src.zip
Copyright © 2014 by John Wiley & Sons. All rights reserved.
34
Organizing Related Classes into Packages
In Java, related classes are
grouped into packages.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
35
Organizing Related Classes into Packages
 To put classes in a package, you must place a line
package packageName;
as the first instruction in the source file containing the
classes.
 Package name
• consists of one or more identifiers separated by periods.
• Usually all lower case
Copyright © 2014 by John Wiley & Sons. All rights reserved.
36
 To put the Financial class into a package named
com.horstmann.bigjava, the Financial.java file
must start as follows:
package com.horstmann.bigjava;
public class Financial
{
. . .
}
Copyright © 2014 by John Wiley & Sons. All rights reserved.
37
Organizing Related Classes into Packages
 A special package: default package
• Has no name
• No package statement
• If you did not include any package statement at the top of your
source file
o its classes are placed in the default package.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
38
Package Names
 Use packages to avoid name clashes:
java.util.Timer
vs.
javax.swing.Timer
 Package names should be unique.
 A good choice for package name:
• turn the domain name in reverse:
com.horstmann.bigjava
• Or write your email address backwards:
edu.sjsu.cs.walters
Copyright © 2014 by John Wiley & Sons. All rights reserved.
39
Syntax 8.1 Package Specification
Copyright © 2014 by John Wiley & Sons. All rights reserved.
40
Packages and Source Files
 The path of a class file must match its package name.
 The parts of the name between periods represent successively
nested directories.
 Base directory:
• holds your program's files
• Place the subdirectory inside the base directory.
• If your homework assignment is in a directory
/home/britney/hw8/problem1
Place the class files for the com.horstmann.bigjava package into
the directory:
o /home/britney/hw8/problem1/com/horstmann/bigjava (UNIX)
o by
OrJohn
c:\Users\Britney\hw8\problem1\com\horstmann\bigjava
Copyright © 2014
Wiley & Sons. All rights reserved.
(Windows)
41
Packages and Source Files
Figure 6 Base Directories and Subdirectories for Packages
Copyright © 2014 by John Wiley & Sons. All rights reserved.
42
Programming Question
 Create a package cs160:
1. Modify both BankAccount.java and CashRegister.java to
include the package statement: package cs160;
2. Copy their main method bodies in corresponding Tester
classes as the last method in classes.
Download classes from class website.
3. Compile these two files and copy the two .class files
generated into a subdirectory called cs160.
cs160
BankAccount.java
BankAccount.class
CashRegister.java
CashRegister.class
Copyright © 2014 by John Wiley & Sons. All rights reserved.
You will find that for
successful compilation you
need to manually create
cs160 folder and put source
(java) files there.
Once compiled, source files
are not required
43

Test if it works:
• From current directory (shell prompt)
$ java cs160.BankAccount
$ java cs160.CashRegister
Copyright © 2014 by John Wiley & Sons. All rights reserved.
44
 Alternative way to create packages (easier and recommended):
1.
Create/modify your java files in any location you want.
E.g. BankAccount.java
2.
Go to shell prompt/command line and navigate (cd) to folder with
source files
Copyright © 2014 by John Wiley & Sons. All rights reserved.
45
3.
Type javac command to compile each source file
E.g javac -d . BankAccount.java
This will automatically create the directory structure and place
.class file in ch8 directory.
some
directory
BankAccount.java
cs160
ch8
BankAccount.class
Copyright © 2014 by John Wiley & Sons. All rights reserved.
46
Answer
package cs160;
import java.util.ArrayList;
BankAccount.java
public class BankAccount{
private double balance;
private int accountNumber;
private static int lastAssignedNumber = 0;
public BankAccount(double balance)
{
this.balance = balance;
lastAssignedNumber++;
accountNumber = lastAssignedNumber;
}
private double getBalance()
{
return balance;
}
public String toString()
{
return "Bank Account No:"+accountNumber+" balance:"+balance;
}
public static void main(String args[]) {
ArrayList<BankAccount> accounts = new ArrayList<BankAccount>();
BankAccount acct1 = new BankAccount(1000.00);
accounts.add(acct1);
BankAccount acct2 = new BankAccount(2000.00);
accounts.add(acct2);
BankAccount acct3 = new BankAccount(3000.00);
accounts.add(acct3);
for(BankAccount acct: accounts)
System.out.print("BankAccount balance before:"+ acct.getBalance());
System.out.println();
}
Copyright
© 2014 by John Wiley & Sons. All rights reserved.
}
47
CashRegister.java
package cs160;
public class CashRegister{
public static final double QUARTER_VALUE = 0.25 ,DIME_VALUE = 0.1, NICKEL_VALUE = 0.05, PENNY_VALUE = 0.01;
private double purchase, payment;
public CashRegister() {
purchase = 0;
payment = 0;
}
public void recordPurchase(double amount){
purchase = purchase + amount;
}
public void receivePayment(int dollars, int quarters,int dimes, int nickels, int pennies) {
payment = dollars + quarters * QUARTER_VALUE + dimes * DIME_VALUE
+ nickels * NICKEL_VALUE + pennies * PENNY_VALUE;
}
public double giveChange(){
double change = payment - purchase;
purchase = 0;
payment = 0;
return change;
}
public static void main(String[] args){
CashRegister register = new CashRegister();
register.recordPurchase(0.75);
register.recordPurchase(1.50);
register.receivePayment(2, 0, 5, 0, 0);
System.out.print("Change: ");
System.out.println(register.giveChange());
System.out.println("Expected: 0.25");
}
Copyright
© 2014 by John Wiley & Sons. All rights reserved.
}
48
 Add package to jar file list
1. Create the jar file
• In the shell prompt (in parent directory of cs160/ch8) type
jar cvf cs160.jar cs160/ch8/*.class
2. Add jar to classpath in DrJava:
•
EditPreferencesResourceLocationsExtraClassPathAddselect cs160.jar ok

Copyright © 2014 by John Wiley & Sons. All rights reserved.
49
Importing Packages
 Can use a class without importing: refer to it by its full
name (package name plus class name):
java.util.Scanner in = new java.util.Scanner(System.in);
• Inconvenient
 import directive lets you refer to a class of a package by
its class name, without the package prefix:
import java.util.Scanner;
• Now you can refer to the class as Scanner without the package
prefix.
• E.g. Scanner in = new Scanner(System.in);
Copyright © 2014 by John Wiley & Sons. All rights reserved.
50
Importing Packages
 Can import all classes in a package:
import java.util.*;
 Never need to import java.lang.
 You don't need to import other classes in the same
package .
Copyright © 2014 by John Wiley & Sons. All rights reserved.
51
Programming Question
 Import packages:
• Write a tester class called PackageImportDemo which will test
importing packages (save this class in a completely different
location than the location you have source/.class files for cs160
package you created)
• Import the package you created and test BankAccount class by
creating a BankAccount object with balance $1000 and printing
the balance by calling toString() method:
Copyright © 2014 by John Wiley & Sons. All rights reserved.
52
Answer
PackageImportDemo.java
import cs160.ch8.BankAccount;
public class PackageImportDemo
{
public static void main(String args[])
{
BankAccount acct = new BankAccount(1000.0);
System.out.println(acct);
}
}
Copyright © 2014 by John Wiley & Sons. All rights reserved.
53
Unit Test Framework
 Compilers cannot check for logical errors:
• whether the results of a program or method are correct.
 So how do you check those errors?
• Developers need to test their programs to ensure that they
behave as expected.
• (+) Sometimes it is simple:
• calling a method in the Interactions Pane to view its results
• (-) Developer should know expected answers.
 A better solution:
• Give the tests the answers you expect, and let the tests
themselves do all the work.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
54
 Unit testing makes this quite easy.
 Unit testing is the testing of single entity (class or method)
 Fast Automation:
• runs test cases significantly faster than human resources.
 You write many small tests that create your objects and assert
that they behave the way you expect in different situations.
 A unit test framework known as JUnit (http://www.junit.org)
automates the process of running these tests, letting you
quickly see whether your program returns the results you
expect.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
55
JUnit
 JUnit: http://junit.org
• A unit testing framework for the Java Programming Language
• Idea: "first testing then coding“
• Open source framework used for writing & running tests.
• Unit tests can be run automatically and they check their own
results and provide immediate feedback.
• Shows test progress in a bar that is green if test is going fine
and it turns red when a test fails.
• Built into some IDEs like BlueJ ,Eclipse and DrJava
• DrJava Junit documentation:
• http://www.drjava.org/docs/user/ch07.html
Copyright © 2014 by John Wiley & Sons. All rights reserved.
56
JUnit
 Philosophy:
• Whenever you implement a class, also make a companion test
class.
• Run all tests whenever you change your code.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
57
JUnit
 In DrJava:
1. Write a JUnit test class
2. Test Current junit test case Document:
Choose the "Test Current Document" command from the Tools menu
to run the tests and view the results.
•
Test all open junit test case documents :
•
Click the "Test" button on the toolbar or choo "Test All Documents"
from the Tools menu
 Output:
• Shown in the Test Output tab
• Each test method turn green if it completes successfully and red if
it fails.
• A progress bar will keep you updated on how many tests have
been run.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
58
JUnit
 Unit tests are any public classes that extend
the junit.framework.TestCase class
 Have any number of methods with names beginning with
the word "test“
Copyright © 2014 by John Wiley & Sons. All rights reserved.
59
JUnit
 Writing a Test Case:
 Choose the "New JUnit Test Case" command from the File
menu
 This automatically generate a template with these
conventions.
 At the top of the file, include:
• import junit.framework.TestCase;
 The main class of the file must:
• be public
• extend TestCase
Copyright © 2014 by John Wiley & Sons. All rights reserved.
60
JUnit
 Methods of this class to be run automatically when the Test
command is invoked must:
•
•
•
•
be public and not static
return void
take no arguments
have a name beginning with "test“
 Test methods in this class can call any of the following
methods (among others):
• void assertTrue (String, boolean)
• issues an error report with the given string if the boolean is false.
• void assertEquals (String, int, int)
• issues an error report with the given string if the two integers are not
equal. The first int is the expected value, and the second int is the
actual (tested) value.
• void fail (String)
• which immediately causes the test to fail, issuing an error report with
the given string.
Copyright © 2014 by John Wiley & Sons. All rights reserved.
61
Simple Test Example
 Simple Test Example
 Suppose you are writing a Calculator class that can
perform simple operations on pairs of integers.




First write testcase class with few tests for it
Then write the Calculator class
Compile both classes
Run the tests to see if they pass
• “Tools Test current document”
Copyright © 2014 by John Wiley & Sons. All rights reserved.
62
CaclulatorTest.java
import junit.framework.TestCase;
public class CalculatorTest extends TestCase
{
public void testAddition()
{
Calculator calc = new Calculator();
// 3 + 4 = 7
int expected = 7;
int actual = calc.add(3, 4);
assertEquals("adding 3 and 4", expected, actual);
}
Caclulator.java
public class Calculator
{
public int add(int a, int b)
{
return a+b;
}
public int divide(int a, int
b)
{
return a/b;
}
}
public void testDivision()
{
Calculator calc = new Calculator();
// Divide by zero shouldn't work
try
{
calc.divide(2, 0);
fail("Should have thrown an exception!");
}
catch (ArithmeticException e) {
// Good, that's what we expect
}
}
}
Copyright © 2014 by John Wiley & Sons. All rights reserved.
63