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 */ } }