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