6.096 Fall 1997
Introduction to Interactive Programming

Solutions to Design Project

Solutions to Collaborative Design Project (Alarm Clock)

Your first job is to design a system of computational objects which together constitute an alarm clock. Your code specification should support:

Overall Design

You should ask yourself the following questions, and your write-up should include answers to each of these:

There are four "kinds of things" in my alarm clock.

  1. Time, a class which encapsulates a time. Note that the identity of a Time object can stay the same even if its value -- its "time" -- changes. Time has a tick method to allow it to be updated by another object, i.e., it knows how to update its value, but not when.
  2. Clock, a class of objects which repeatedly asks its Time to tick(), and which provides a getTime() method to make its current Time available, e.g., to a clock display.
  3. AlarmBell, an interface for an object that can ring() (and go quiet()). A simple one might print a message to the screen, while a more complex one might actually ring the system bell.
  4. Alarm, a class whose instances poll their Clocks to see whether it is time to go off, and (if appropriate) ask their AlarmBells to ring().

Instances of Clock, Alarm, and AlarmBell are all self-animating. A Clock repeatedly asks its Time to tick(); an Alarm repeatedly checks its Clock to see whether it is time to ring (and, if so, notifies its AlarmBell); an AlarmBell continuously checks to see whether it is supposed to be ringing (and rings, if appropriate). By itself,a Time doesn't do anything; it is just a convenient abstraction to keep track of minutes and hours, etc.

More details on each of these classes/interfaces are given below.

User's Manual

There should be two parts to your design for each of the design projects: the alarm clock and the free design problem. The first is for the user of your class(es). This documentation should specify what your object types are and how they are to be used. This should read something like a user's manual for your object(s). You may also wish to include in this section any hooks that may be available for extending your object(s).

To use this alarm clock, you must:

  1. Create an instance of class Clock (supplying it with an optional ClockDisplay and Time).
  1. Create an instance of class Alarm, supplying it with a Clock instance (and an optional Time and AlarmBell).

For example, here is the minimal version:

Clock clock = new Clock();
Alarm alarm = new Alarm(c);

And here everything is explicitly created (which future implementors may want to do when they develop fancy extensions to the given classes):

ClockDisplay display = new ClockDisplay();
Time clockTime = new ClockTime(24,0); // midnight
Clock clock2 = new Clock(display, clockTime);

Time alarmTime = new Time(12,0); // noon
AlarmBell bell = new AlarmBell();
Alarm alarm2 = new Alarm(clock2, clockTime, bell);

Multiple alarms may be created for a single clock. To set an alarm, use the following method of Alarm:

public void setTime( Time t );

For example:

Time brightAndEarly = new Time(6, 0); // 6AM
alarm.setTime(brightAndEarly);

// this is a second alarm that uses the same clock.
Time teaTime        = new Time(16,0); // Tea Time
Alarm alarm3 = new Alarm(c);
alarm3.setTime(teaTime);

You can turn the alarm on with

public void turnOn();

and off with

public void turnOff();

These methods do not change the time for which the alarm is set.

Examples:

alarm.turnOn();
alarm.turnOff();

Finally, the clock's time can be set using the following method of Clock:

public void setTime( Time t );

Here is an example:

Time midnight = new Time(24,0); 
clock.setTime(midnight);

Implementor's Specifications

The second, and more extensive, piece of documentation describes the details of your design, e.g., for a future implementor. For this section, you should turn in a complete listing of the object types (classes) that you define, including for each a complete list of fields and methods.

For each class, you should provide documetation indicating what role instances of the class are supposed to play and how they are intended to be used. You should describe the state of instances at the time that they are created as well as how they are expected to evolve over time.

For each field, you should describe its purpose, its visibility (e.g., public or private), and any relevant information about its initial state or evolution. If it is not clear, you should mention which methods change its value.

For each method, you should specify the argument and return types as well as the relationship between them. You should also list what the method does and, if it interacts with the object's fields or other methods, detail these interactions.

When one class relies on another, you should specify these interdependencies.

For objects that are self-animating, you should describe their autonomous activity.

class Time is a convenient abstraction to keep track of minutes and hours, etc.; ie., the components of a time. It uses a 24-hour clock, no seconds.

Note that the identity of a Time object can stay the same even if its value -- its "time" -- changes. Time has a tick method to allow it to be updated by another object, i.e., it knows how to update its value, but not when.

/*
 * Class Clock
 * ===========
 * This is an animate class responsible for measuring time.
 * It interacts with a Time object, which stores the current
 * hour and minute, and a ClockDisplay object, which knows how
 * display the Time object.
 */
public class Clock implements Runnable {
    // fields are protected for safety reasons
    protected Thread spirit;
    protected Time time;
    protected ClockDisplay display;
    // First clock constructor.  Constructs a default Time
    // of 12:00 pm and a default ClockDisplay. 
    public Clock();
    // Second clock constructor.  Accepts a user-defined 
    // ClockDisplay object and Time object.
    public Clock(ClockDisplay d, Time t);
    // Method required to be Runnable.
    // Calls the showTime method of the ClockDisplay,
    // sleeps for a minute, and then updates the
    // current Time by calling tick().
    public void run();
    // completely change the current time
    public void setTime( Time newTime );
    // return the current time
    public Time getTime();
}
/* 
 * Class Alarm
 * ===========
 * This self-animating class is the brains behind the whole
 * operation.  It is responsible for handling user requests
 * to set the alarm time, and turn the alarm mode on and off.  
 * It must monitor the current time and tell the AlarmBell
 * when to start ringing and tell it to be quiet once the
 * user turns off alarm mode.
 */
public class Alarm implements Runnable {
    // fields are protected for security reasons.
    protected Clock clock;
    protected Time alarmTime;
    protected boolean isOn;
    protected AlarmBell bell;
    // The first constructor takes no arguments.
    // It constructs a default alarm time of 12:00 noon
    // and a default bell.
    public Alarm( Clock clock );
    // The second constructor accepts a predefined alarm time 
    // and AlarmBell as well.
    public Alarm( Clock clock, Time time, AlarmBell bell );
    // This is the method required to be Runnable.
    // While isOn is true, it monitors the current time of the Clock 
    // using the getTime() method, compares it to alarmTime using the
    // equals() method, and notifies the AlarmBell using ring()
    // when the times match.
    public void run();
    // the alarm time can be set by the user using this method.
    // Modifies the field alarmTime.
    public void setAlarm( Time time );
    // turn alarm mode on by calling this method.  It sets the
    // boolean isOn to true.
    public void turnOn();
    // turn alarm mode off by setting the boolean isOn to false.
    // Also tell the AlarmBell to be quiet() (since it may be going off).
    public void turnOff();
}
/*
 * Class AlarmBell
 * ===============
 * This is an animate class responsible for 
 * making noise.  It rings continuously from 
 * the time ring() is called until quiet() is called.
 * These methods are called by Alarm.  AlarmBells
 * start up in the "not ringing" state.  
 */
public class AlarmBell implements Runnable {
    // animacy storage
    protected Thread spirit;
    // a boolean which keeps track of whether or not
    // the AlarmBell should be ringing.  Set by methods
    // ring() and quiet() and used by the run() method.
    protected boolean isRinging = false;
    // constructor
    public AlarmBell();
    // a method that Alarm uses to tell me to start ringing.
    public void ring();
    // a method that Alarm uses to tell me to be quiet.
    public void quiet();
    // method needed to be Runnable.
    // contains the magic to ring the bell.
    public void run();
}
/*
 * Class Time
 * ==========
 * Time is an inanimate class responsible for storing an
 * hour/minute pair.  The values can be specified
 * at construction time or changed on the fly.
 * Methods are provided to advance the time, to compare 
 * two times to see if they are equal (since the fields 
 * are protected), and to detect invalid hour/minute 
 * settings (for internal use only).
 */
public class Time {
    /*
     * These are protected so that external classes
     * can't meddle with the values, but subclasses can
     * still access them.  (Future implementors may
     * want seconds, time zone adjustments or other 
     * advances features.)
     */
    protected int hours, minutes;
    /*
     * Default constructor.  Should be equivalent to
     * calling the full constructor and giving it 
     * 12:00 noon.
     */
    public Time();
    /* 
     * The other constructor accepts hours and minutes
     * for dynamic initialization.
     */
    public Time( int hours, int minutes );
    /* 
     * A method is provided to change the time.
     */
    public void setTime( int hours, int minutes );
    /* 
     * A method to advance by the smallest unit of time.
     * Responsible for keeping fields in the correct range.
     */
    public void tick();
    /*
     * A convenience method provided for external 
     * classes to detect if two times are equal -- 
     * since the fields are not externally visible.
     * Returns true when the two times are equivalent.
     */
    public boolean equals(Time t) ;
    /*
     * This method is protected so that only this class
     * and its subclasses can access it.  Checks whether
     * the given hour/minute pair is valid.
     */
    protected void checkValidity( hours, minutes ) throws BadTimeException;
}
/* 
 * Class BadTimeException
 * ======================
 * A subclass of Exception that can be thrown
 * whenever the user specifies an invalid
 * time.  Used by class Time.
 */
public class BadTimeException extends Exception;
/* 
 * Class ClockDisplay
 * ==================
 * An inanimate class responsible for knowing how
 * to display a given time.  The display will not
 * change until specifically told to (using the
 * showTime method).
 */
public class ClockDisplay {
/* 
 * The only thing we require of the ClockDisplay
 * is that it can accept a Time object.  This way,
 * future implementors can choose between analog,
 * digital, or any other form of display.  Clock 
 * calls this method and passes it a Time object
 * whenever a new time should be displayed. 
 */
public void showTime( Time t );
}

Solutions to Individual Design Projects

There are no staff solutions to individual design projects.

[Course Home Page] [Lecture Notes Index]


This course is a part of Lynn Andrea Stein's Rethinking CS101 project at the MIT AI Lab and the Department of Electrical Engineering and Computer Science at the Massachusetts Institute of Technology.

Questions or comments:
<cs101-webmaster@ai.mit.edu>
Last modified: Fri Oct 10 00:28:29 EDT 1997