CSC 307 Lecture Notes Week 7
Design for Independent, Incremental Testing
Refining Model Design Using the Java Library
A Key Design Patterns for 307 Projects
public class SomeModelClass implements Serializable {
...
}
model = new SomeModelClass(); /* Put some data in model ... */ FileOutputStream outFile = new FileOutputStream( "model.dat"); ObjectOutputStream outStream = new ObjectOutputStream(outFile); outStream.writeObject(model);
FileInputStream inFile =
new FileInputStream("model.dat");
ObjectInputStream inStream =
new ObjectInputStream(inFile);
model = (SomeModelClass)
inStream.readObject();
Figure 1: Event diagramming notation.
Figure 2: User input data collection and validation for scheduling an event.
public class OKScheduleEventButtonListener implements ActionListener {
/**
* Construct this with the given Schedule model and parent dialog view.
* Access to the model is for calling its scheduleEvent method. Access to
* the parent view is for gathering data to be sent to scheduleEvent.
*/
public OKScheduleEventButtonListener(Schedule schedule,
ScheduleEventDialog dialog) {
this.schedule = schedule;
this.dialog = dialog;
}
/**
* Respond to a press of the OK button by calling ScheduleEvent with a new
* Event. The Event data are gathered from the JTextFields and JComboBox
* in the parent dialog.
*/
public void actionPerformed(ActionEvent e) {
try {
schedule.scheduleEvent(
new caltool.schedule.Event(
dialog.getTitle(), // Title as a string
dialog.getStartDate(), // Start date as a Date
dialog.getEndDate(), // Start date as a Date
dialog.getCategory(), // Category as a Category
dialog.getLocation() // Location as a string
)
);
}
catch (ScheduleEventPrecondViolation errors) {
dialog.displayErrors(errors);
}
}
/** The companion model */
protected Schedule schedule;
/** The parent view */
protected ScheduleEventDialog dialog;
}
public class Schedule extends Model {
...
/**
* ScheduleEvent adds the given Event to the given CalendarDB, if an event
* of the same start date and title is not already scheduled.
*
* pre: Details in next week's notes
*
* post: Details in next week's notes
*/
public void scheduleEvent(Event event)
throws ScheduleEventPrecondViolation {
/*
* Clear out the error fields in precond violation exception object.
*/
scheduleEventPrecondViolation.clear();
/*
* Throw a precond violation if the validly check fails on the start or
* end date.
*/
if (validateInputs(event).anyErrors()) {
throw scheduleEventPrecondViolation;
}
/*
* Throw a precond violation if an event of the same start date and
* title is already scheduled.
*/
if (alreadyScheduled(event)) {
scheduleEventPrecondViolation.setAlreadyScheduledError();
throw scheduleEventPrecondViolation;
}
/*
* Throw a precond violation if there is no currently active calendar.
* Note that this condition will not be violated when interacting
* through the view, since the 'Schedule Event' menu item is disabled
* whenever the there is no active calendar.
*/
if (calDB.getCurrentCalendar() == null) {
scheduleEventPrecondViolation.setNoActiveCalendarError();
throw scheduleEventPrecondViolation;
}
/*
* If preconditions are met, add the given event to the currently
* active calendar.
*/
calDB.getCurrentCalendar().add(event);
}
}
package caltool.schedule;
import caltool.PrecondViolation;
import java.util.*;
/****
*
* Class ScheduleEventPrecondViolation defines and exception containing error
* conditions for the Schedule.scheduleEvent method. It contains a list of
* the specific error messages that may be output in response to a precondition
* having been violated by a call th scheduleEvent.
*
*/
public class ScheduleEventPrecondViolation extends Exception
implements PrecondViolation {
/**
* Construct this by initializing the error message list to an empty list,
* initializing the numErrors count to 0, and initializing local copies of
* the error message text for each of the possible errors from
* Schedule.scheduleEvent.
*/
public ScheduleEventPrecondViolation() {
errors = new ArrayList();
alreadyScheduledMessage = new String(
"An event of the given start date and title is already scheduled.");
invalidStartDateMessage = new String(
"Invalid start date.");
invalidEndDateMessage = new String(
"Invalid end date.");
noActiveCalendarMessage = new String(
"There is no active calendar in the Calendar Tool workspace.");
numErrors = 0;
}
/*-*
* Implemented interface methods.
*/
/**
* Return the error list.
*/
public String[] getErrors() {
return (String[]) errors.toArray(new String[1]);
}
/**
* Clear all error messages.
*/
public void clear() {
errors = new ArrayList();
numErrors = 0;
}
/**
* Return true if any errors have been set.
*/
public boolean anyErrors() {
return (numErrors > 0);
}
/**
* Return the number of errors.
*/
public int numberOfErrors() {
return numErrors;
}
/*-*
* Error-setting methods
*/
/**
* Set the already scheduled error message.
*/
public void setAlreadyScheduledError() {
errors.add(alreadyScheduledMessage);
numErrors++;
}
/**
* Set the invalid start date error message.
*/
public void setInvalidStartDateError() {
errors.add(invalidStartDateMessage);
numErrors++;
}
/**
* Set the invalid end date error message.
*/
public void setInvalidEndDateError() {
errors.add(invalidEndDateMessage);
numErrors++;
}
/**
* Set the no active calendar error message.
*/
public void setNoActiveCalendarError() {
errors.add(noActiveCalendarMessage);
numErrors++;
}
/*-*
* Data fields
*/
/** List of current error messages */
protected ArrayList errors;
/** Error message count */
protected int numErrors;
/** Error message for event of same date,title already scheduled */
protected String alreadyScheduledMessage;
/** Error message for invalid start date */
protected String invalidStartDateMessage;
/** Error message for invalid end date */
protected String invalidEndDateMessage;
/** Error message for no currently active calendar in the workspace */
protected String noActiveCalendarMessage;
}
package caltool;
/****
*
* Interface PrecondViolation defines the methods that all precondition
* violation exceptions must implement.
*
*/
public interface PrecondViolation {
/**
* Return the concrete error list for precondition violation. Each
* position in the list corresponds to violation of a particular
* precondition clause.
*/
public String[] getErrors();
/**
* Clear out all of the error messages in this.
*/
public void clear();
/**
* Return true if one or more error messages has been set.
*/
public boolean anyErrors();
/**
* Return the number of error messages.
*/
public int numberOfErrors();
}
interface Observer {
public void update(
Observable o,
Object arg)
}
class Observable {
void addObserver(Observer o)
void setChanged()
boolean hasChanged()
void notifyObservers()
void notifyObservers(Object arg)
}
public class View implements Observer {
. . .
}
public class Model extends Observable implements Serializable {
. . .
}
public class UserCalendar extends Model {
. . .
public void add(ScheduledItem item) {
. . .
items.add(item);
setChanged();
}
}
. . .
public class OKScheduleEVentButtonListener implements ActionListener {
public void actionPerformed() {
try {
schedule.scheduleEvent(
new caltool.schedule.Event(
...
)
);
}
. . .
schedule.notifyObservers();
. . .
}
}
. . .
public class MonthlyAgenda extends View {
public MonthlyAgenda(caltool.view.View view, UserCalendar userCalendar) {
. . .
userCalendar.addObserver(this)
}
public void update(Observable o, Object arg) {
/* Get items for this month from MonthylyAgenda model and update display */
}
}