Paragrafo 8.7

annuncio pubblicitario
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
Paragrafo
presentazione
8.7
8.7
L
e asserzioni costituiscono un meccanismo che può essere sfruttato per
rilevare errori logici nei programmi. L’idea è abbastanza semplice: in
qualsiasi punto del programma può essere inserita un’istruzione assert,
con la seguente sintassi:
assert
<espressione booleana>
L’<espressione booleana> rappresenta la condizione che deve essere
verificata quando l’esecuzione del programma è corretta. Quando l’istruzione viene
eseguita, se tale espressione è valutata true l’esecuzione prosegue regolarmente, altrimenti viene sollevato un errore AssertionError.
Questo paragrafo introduce gli studenti all’uso delle asserzioni.
PARAGRAFO 8.7
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
8.7 Sample Development
469
Sample Development
8.7 Sample Development
Keyless Entry System
We will develop a program that simulates a secure keyless entry system for a dormitory. Inside the entrance hall of a dorm, there is an entry system where the dorm residents must enter their names, room numbers, and passwords. Upon entry of valid data,
the system will unlock the inner door that leads to the dorm’s living quarters. To implement this program, two helper classes are provided. The Door class simulates unlocking of the inner door. The Dorm class manages resident information. An instance of the
Dorm class is capable of adding and deleting resident information, reading and saving
resident information from and to a file, and retrieving information if given the resident’s name. We can verify the validity of the entered data by checking them against
the information kept by a Dorm object.
We can turn our simulation program into a real one by replacing the Door
class with a class that actually controls the door. Java provides a mechanism
called Java Native Interface (JNI) which can be used to embed a link to a lowlevel device driver code, so calling the open method actually unlocks the
door.
Problem Statement
Implement a sentry program that asks for three pieces of information: resident’s
name, room number, and a password. A password is any sequence of characters
ranging in length from 4 to 8 and is unique to an individual dorm resident. If
everything matches, then the system unlocks and opens the door.We assume no
two residents have the same name. Use the provided support classes Door and
Dorm.
Overall Plan
To provide a complete system, we actually have to write two separate programs. The
first one is the administrative module for adding, removing, and updating the resident
information. The second is the user module that interacts with the residents. Figure 8.8
shows the program diagrams for the two modules.
In this section, we implement the user module. The administrative module is left
as an exercise. To begin our development effort, we must first find out the capabilities
of the Dorm and Door classes. Also, for us to implement the class correctly, we need the
specification of the Resident class.
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
470
Chapter 8
Exceptions and Assertions
8.7 Sample Development—continued
User module
Dorm
Resident
Door
Administrative
module
A helper class
provided to us
Dorm
A class we
implement
Resident
One or more classes
we implement
Figure 8.8 Program diagrams for the user and administrative modules. Notice the same Dorm and
Resident classes are used in both programs. User and administrative modules will include one or more
classes (at least one is programmer-defined).
Resident
The Resident class maintains information on individual dorm residents. We will be dealing with many instances of this class in the program. A password assigned to a resident
must be a sequence of 4 to 8 characters. For this class to work properly with the Dorm
class, the class must include these public methods:
Public Methods of Resident
public Resident( )
Default constructor that creates a Resident object with name
= “unassigned”, room = “000”, and id = “@13&”.
public Resident(String name, String room, String password)
throws IllegalArgumentException
Creates a Resident object with the passed values.
IllegalArgumentException is thrown when the given password has less
than four or more than eight characters.
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
8.7 Sample Development
471
public void setName(String name)
Assigns the name.
public void setPassword(String id)
throws IllegalArgumentException
Assigns the password. IllegalArgumentException is thrown when the
given password has less than four or more than eight characters.
public void setRoom(String room)
Assigns the room.
public String getName( )
Returns the name.
public String getPassWord( )
Returns the password.
public String getRoom( )
Returns the room number.
One important restriction to the Resident class is the requirement for the class to
implement the Serializable interface. Because the Resident objects are saved to a file,
Java requires the class definition to include the phrase implements Serializable as
import java.io.*;
class Resident implements Serializable {
...
}
Details on the significance of the clause implements Serializable will be given
when we discuss the file input and output in Chapter 12.
For any object we need to save to a file, its class definition must include the phrase
implements Serializable.
Dorm
The Dorm class is a helper class provided to us. A Dorm object is capable of managing
a list of Resident objects. It allows the client to add, delete, and retrieve Resident
objects. In addition, it is capable of saving a list to a file or reading a list from a file. By
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
472
Chapter 8
Exceptions and Assertions
8.7 Sample Development—continued
having these file input and output features, our program can work with different lists of
residents much as a word processor can work with different documents (files). The class
definition is as follows:
Public Methods of Dorm
public Dorm( )
Default constructor that creates a Dorm object.
public Dorm(String filename)
Creates a Dorm object with the resident list read from the file with the
name filename.Throws FileNotFoundException when the
designated file cannot be found and IOException when the file cannot
be read.
public void openFile(String filename)
Reads the resident list from the designated file.Throws
FileNotFoundException when the designated file cannot be found and
IOException when the file cannot be read.
public void saveFile(String filename)
Saves the resident list to the designated file. Throws IOException when the
file cannot be saved.
public void add(Resident resident)
Adds the resident to the list. Throws IllegalArgumentException
when a resident with the same name already exists in the list. We do not allow
duplicate names. Every resident must have a unique name.
public void delete(String name)
Deletes the designated resident from the list. If no such resident is in the list,
nothing happens.
public Resident getResident(String name)
Returns the Resident object with the given name. Returns null if no
matching Resident is found.
public String getResidentList( )
Returns a list of residents as a String. A line separator is used after each
resident. For each resident, the list contains his or her name, room number,
and password.
Door
The Door class is another helper class. It simulates the opening of the door. In a real
control program, a Door object can have an embedded low-level device driver code,
wu23399_ch08.qxd 12/15/06 19:58 Page 473
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
8.7 Sample Development
473
so it really opens the door. The class definition is as follows:
Public Methods of Door
public Door( )
Default constructor that creates a new Door object.
public void open()
Opens the door. For this simulator class, it displays a simple message dialog.
overall
design
Now let’s study the overall design of the program. In addition to the given helper
classes and the Resident class, what other classes should we define for this program?
As the number of classes gets larger, we need to plan the classes carefully. For this
program, we will define a controller class named Ch8EntranceMonitor whose instance
will manage all other objects. We will set this class as the program’s main class. The user
interface of the program is handled by the InputHandler class. Its instance is used to
allow the user to enter his or her name, room number, and password. After the required
input data are entered by the user, a Ch8EntranceMonitor checks the validity of the
input data with help from a service Dorm object. If the Dorm object confirms the input
data, the controller then instructs another service object, an instance of Door, to open
the door. The following is our working design document, and Figure 8.9 is the program
diagram.
User module
InputHandler
Ch8EntranceMonitor
Dorm
JOptionPane
Door
Resident
Figure 8.9 The program diagram for the Ch8EntranceMonitor program. There are three classes in the
user module.
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
474
Chapter 8
Exceptions and Assertions
8.7 Sample Development—continued
program
classes
Design Document: Ch8EntranceMonitor
Class
Purpose
Ch8EntranceMonitor
The top-level control object manages other objects
in the program.This is an instantiable main class.
The given predefined class simulates the opening of
a door.
The given predefined class maintains a list of
Resident objects.
The user interface class is for handling input
routines.
Door
Dorm
InputHandler
We will implement the user module in three major steps:
development steps
1. Define the Resident class and explore the Dorm class. Start with a program
skeleton to test the Resident class.
2. Define the user interface InputHandler class. Modify the top-level control class
as necessary.
3. Finalize the code by making improvements and tying up loose ends.
Step 1 Development: Program Skeleton
step 1
design
step 1 code
Our first task is to find out about the given Dorm class. (The Door class is a very simple
simulator class so there’s not much to explore.) To be able to test-run the Dorm class,
we must provide the Resident class, so this will be our first step. The purpose of the
skeleton main class in this step is to verify the operations of the Dorm class.
The specification for the Resident class was given to us, so our task is to implement
it according to the specification. No design work is necessary. When we can interact with
an instance of the Dorm class correctly, it confirms that our implementation of the
Resident class is working. To verify the key operations of the Dorm class, the top-level
supervisor object Ch8EntranceMonitor will open a file and list the contents of the file.
Here’s the Resident class:
/*
Chapter 8 Sample Development: Keyless Entry System.
File: Resident.java
*/
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
8.7 Sample Development
import java.io.*;
class Resident implements Serializable {
private String name;
private String room;
private String password;
public Resident( ) {
this("unassigned", "000", "@13&");
}
Data members
Constructors
public Resident(String name, String room, String pwd)
throws IllegalArgumentException {
setName(name);
setRoom(room);
setPassword(pwd);
}
public String getName( ) {
return name;
}
Accessors
public String getPassword( ) {
return password;
}
public String getRoom( ) {
return room;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String pwd) {
int length = pwd.length();
if (length < 4 || length > 8) {
throw new IllegalArgumentException();
} else {
this.password = pwd;
}
}
public void setRoom(String room) {
this.room = room;
}
}
Mutators
475
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
476
Chapter 8
Exceptions and Assertions
8.7 Sample Development—continued
The skeleton main class is defined as follows:
/*
Chapter 8 Sample Development: Keyless Entry System. (Step 1)
File: Ch8EntranceMonitor.java
*/
import javax.swing.*;
import java.io.*;
class Ch8EntranceMonitor { //Step 1 main class
private Dorm manager;
private Scanner scanner;
public Ch8EntranceMonitor( ) {
manager = new Dorm();
scanner = new Scanner(System.in);
}
public static void main(String[] args) {
Ch8EntranceMonitor sentry = new Ch8EntranceMonitor();
sentry.start();
}
public void start( ) {
start
openFile( );
String roster = manager.getResidentList();
System.out.println(roster);
}
private void openFile( ) {
String filename;
openFile
while (true) {
System.out.println("File to open ('x' to cancel):");
filename = scanner.next();
if (filename.equals("x")) {//input routine is canceled
System.out.println("Program is canceled.");
System.exit(0);
}
wu23399_ch08.qxd 12/15/06 19:58 Page 477
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
8.7 Sample Development
477
try {
manager.openFile(filename);
return;
} catch (FileNotFoundException e) {
System.out.println("No such file");
} catch (IOException e) {
System.out.println("Error in reading file");
}
}
}
step 1 test
The purpose of step 1 testing is to verify that the Dorm class is used correctly to
open a file and get the contents of the file. To test it, we need a file that contains the resident information. A sample test file can be created by executing the following program,
which we can modify to create other test data files.
/*
Chapter 8 Sample Development: Keyless Entry System.
A simple class to create dummy test data.
File: SampleCreateResidentFile.java
*/
import java.util.*;
import java.io.*;
class SampleCreateResidentFile {
public static void main(String[] args)throws IOException {
Resident res;
Dorm manager = new Dorm( );
res = new Resident("john", "1-101", "3457");
manager.add(res);
res = new Resident("java", "1-102", "4588");
manager.add(res);
res = new Resident("jill", "3-232", "8898");
manager.add(res);
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
478
Chapter 8
Exceptions and Assertions
8.7 Sample Development—continued
res = new Resident("jack", "3-232", "8008");
manager.add(res);
Scanner scanner = new Scanner(System.in);
System.out.println("Save to which file:");
String filename = scanner.next();
manager.saveFile(filename);
System.exit(0); //terminate the program
}
}
Step 2 Development: Create the User Interface
step 2
design
In the second development step, we will implement the user interface class
InputHandler, whose task is to get three pieces of information. The main controller
Ch8EntranceMonitor will call an InputHandler to get input data. An InputHandler
will then go through a sequence of getting the three pieces of data. Once the data are
entered, Ch8EntranceMonitor will ask the InputHandler for these data. The logic of
Ch8EntranceMonitor can be expressed as follows:
InputHandler input = new InputHandler();
. . .
input.getInput();
String name = input.getName();
String room = input.getRoomNumber();
String pwd = input.getPassword();
Given the input data, we can check for the match as
Dorm manager = new Dorm();
. . .
Resident res = manager.getResident(name);
if (res == null) {
System.out.println("Invalid Entry");
wu23399_ch08.qxd 12/15/06 19:58 Page 479
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
8.7 Sample Development
479
} else if (res.getName().equals(name) &&
res.getRoom().equals(room) &&
res.getPassword().equals(password)) {
door.open();
} else {
System.out.println ("Invalid Entry");
}
step 2 code
The getInput method of the InputHandler class calls the scanner three times to
get the name, room, and password. Each input is recorded in the corresponding data
member. The accessors, such as getName, will simply return the value of the requested
data member.
We will list first the InputHandler class and then the modified Ch8EntranceMonitor class. Here’s the InputHandler class:
/*
Chapter 8 Sample Development: Keyless Entry System
File: InputHandler.java
*/
import java.util.*;
class InputHandler {
private static final String BLANK = "";
private
private
private
private
Data members
String name;
String room;
String pwd;
Scanner scanner;
public InputHandler( ) {
Constructor
name = BLANK;
room = BLANK;
pwd = BLANK;
scanner = new Scanner(System.in);
}
public void getInput( ) {
System.out.print("Enter Name:");
name = scanner.next();
System.out.print("Enter Room No.:");
room = scanner.next();
System.out.print("Enter Password:");
pwd = scanner.next();
}
getInput
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
480
Chapter 8
Exceptions and Assertions
8.7 Sample Development—continued
public String getName( ) {
Accessors
return name;
}
public String getRoom( ) {
return room;
}
public String getPassword( ) {
return pwd;
}
}
The main class is now modified to control an InputHandler object and to check entered information as the resident list maintained by a Dorm object. Here’s the step 2
Ch8EntranceMonitor class:
/*
Chapter 8 Sample Development: Keyless Entry System.
File: Ch8EntranceMonitor.java (Step 2)
*/
import java.util.*;
import java.io.*;
class Ch8EntranceMonitor {
private Dorm
manager;
private Door
door;
Data members
private InputHandler input;
private Scanner scanner;
public Ch8EntranceMonitor( ) {
manager
scanner
input
door
}
=
=
=
=
new
new
new
new
Dorm();
Scanner(System.in);
InputHandler();
Door();
Constructors
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
8.7 Sample Development
public static void main(String[] args) {
Ch8EntranceMonitor sentry = new Ch8EntranceMonitor();
sentry.start();
}
public void start( ) {
start
openFile( );
String roster = manager.getResidentList(); //TEMP
System.out.println(roster); //TEMP
processInputData();
}
private void openFile( ) {
String filename;
openFile
while (true) {
System.out.println("File to open ('x' to cancel):");
filename = scanner.next();
if (filename.equals("x")) {//input routine is canceled
System.out.println("Program is canceled.");
System.exit(0);
}
try {
manager.openFile(filename);
return;
} catch (FileNotFoundException e) {
System.out.println("No such file");
} catch (IOException e) {
System.out.println("Error in reading file");
}
}
}
private void processInputData( ) {
String name, room, pwd;
while (true) {
input.getInput();
name = input.getName();
room = input.getRoom();
pwd = input.getPassword();
processInputData
481
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
482
Chapter 8
Exceptions and Assertions
8.7 Sample Development—continued
validate(name, room, pwd);
}
}
private void validate(String name, String room, String password) {
Resident res = manager.getResident(name);
validate
if (res == null) {
System.out.println("Invalid Entry");
} else if (res.getName().equals(name) &&
res.getRoom().equals(room) &&
res.getPassword().equals(password)) {
door.open();
} else {
System.out.println("Invalid Entry");
}
}
}
step 2 test
Notice that the loop inside the processInputData method is an infinite loop. In
other words, when the program starts, it will execute indefinitely. To terminate such a
program, you must either close the Command window or select an appropriate menu
choice (or click on a toolbar icon) in your Java IDE. We will discuss another way to terminate the program in step 3.
The purpose of step 2 testing is to verify the correct behavior of an InputHandler
object. We need to test both successful and unsuccessful cases. We must verify that the
door is in fact opened when valid information is entered. We must also verify that the
error message is displayed when there’s an error in input. We should test invalid cases
such as entering nonexistent name, corrent name but wrong password, not entering all
information, and so forth.
Step 3 Development: Improve and Finalize
There are several key improvements we can make to the program. The first and foremost
is the improved user interface. Instead of getting three pieces of data individually by
using a scanner, it would be nicer to have a frame window such as the one shown in
Figure 8.10, where the user can enter all three pieces of information.We will describe how
to develop such a frame window in Chapter 14.
Java - Fondamenti di programmazione
C. Thomas Wu
Copyright © 2009 - The McGraw-Hill Companies srl
Summary
483
Another improvement is to allow the administrator to terminate the program by
entering special code.This is left as an exercise.
Figure 8.10 A frame window that allows the user to enter the three pieces of information together.
Notice the input entered for the password is displayed back to the user as a sequence of asterisks.
S u m m a r y
•
•
•
•
•
•
•
Two techniques to improve program reliability are exception handling and
assertion.
Exception handling is another type of control flow.
An exception represents an error condition, and when it occurs, we say an
exception is thrown.
A thrown exception must be handled by either catching it or propagating it to
other methods.
If the program does include code to handle the thrown exceptions, then the
system will handle them.
A single method can be both a catcher and a propagator of an exception.
The standard classes described or used in this chapter are
Throwable
RuntimeException
Error
IllegalArgumentException
Exception
InputMismatchException
IOException
•
•
The assertion feature is new to Java 2 SDK 1.4. You must use this version of
the compiler to use assertions in the program.
The assertion feature is used to detect internal logic errors.
Scarica