CMPS 144L Spring 2020
Lab #5: The Clock Class

Provided Java Classes

Provided are the following familiar Java classes, each one a child of the one before it:

For your convenience, next is shown the headings of those public constructors and methods of RollOverCounter (including those that were inherited) that are relevant to this lab. The names of the methods and formal parameters are such that you can probably remember their intended behaviors; if not, view the source code file(s) to see full descriptions.


Your Task

Your job is to complete the Clock class in stages, as described below. To test your work, you can use ClockApp. (A user's interaction with this application shown at the bottom of this page.)

An instance of the Clock class represents a clock that keeps the time of day to a precision of one second. The approach taken is to represent the time using three components:

You will notice that three instance variables are declared in the Clock class, corresponding to the three components mentioned above. Each of them is declared to be of type RollOverCounter, which should not surprise you, given how many times this idea has been mentioned during lecture.

In completing the Clock class, it is recommended that you do things in the order suggested below. After each step, you should use the ClockApp to "verify" that you have completed that step correctly.

Step 1: Complete the constructor and the three getX() (X = Hour, Minute, Second) observer methods (one of which is already provided in full). Keep in mind that the three instance variables are of type RollOverCounter, not of type int. Also recall that the number of hours in a day is 24, the number of minutes in an hour is 60, and the number of seconds in a minute is 60. These are all relevant in initializing the three instance variables.

It is recommended, although not required, that the constructor make use of the setTo() method, in which case you would want to complete that, too. And it would be a good idea for the setTo() method to make use of the three setXTo() methods (X = Hour, Minute, Second).

Step 2: Complete the tick() mutator method, which advances the clock by one second. This is where the "rollover" behavior of the three counters becomes relevant. Being instances of RollOverCounter, each one "automatically" rolls over, when appropriate, in reaction to its increment() method being invoked.

Step 3: Complete the toString24() method, which returns a string that indicates the time of day in 24-hour notation, which is of the form hh:mm:ss in which the hour, minute, and second are shown using two-digit numbers, with leading zeros if necessary. (A provided private method, withLeadingZeros(), should be helpful here.) Examples are

15:45:03   00:09:57   21:32:19

Step 4: Complete the toStringAmPm() method, which returns a string that indicates the time of day in AM/PM notation, which is of the form hh:mm:ssXM (X = 'A' or 'P') in which the hour, minute, and second are shown using two-digit numbers (with leading zeros, if necessary, for minute and second, but not hour). Examples (corresponding to the examples shown above) are

3:45:03PM   12:09:57AM   9:32:19PM

Step 5: If you did not complete all four methods whose name begins with set in an earlier step, do that now.

Step 6: Complete the methods setTo24Mode() and setToAmPmMode(), each of which is intended to set the clock's display mode. The idea is that, if the clock is in 24-hour mode (respectively, AM/PM mode), a call to the toString() method should return the same string as a call to the toString24() (respectively, toStringAmPm()) method.

Now, how is a Clock object supposed to "remember" which mode it is in? Do whatever is necessary to give a Clock that capability and complete the two methods accordingly. When a Clock is created, it should be in 24-hour mode.

Step 7: Assuming, as is likely, that your four set methods (and constructor, for that matter) do nothing to prevent the clock's hour, minute, and second attributes from being set to nonsensical values (e.g., -5, 86), do something about it. Specifically, make it so that any attempt to set any of the clock's attributes to a nonsensical value results in an IllegalArgumentException being thrown. The syntax is

throw new IllegalArgumentException()

There are two basic approaches, one of which fixes the problem at its source, which is the BoundedCounter class. The other approach is like treating a symptom that will recur again and again (in other clients of classes that are descendants of the BoundedCounter class). You can choose either one.

Option 1: Correcting the problem at its source:
The fact that it is even possible for a call to a RollOverCounter's setTo() method to cause its value to go outside the intended range reveals a weakness in its parent class, BoundedCounter. This issue was addressed in Activity #3 of Lab #3, where you were given the task of modifying the BoundedCounter class so that an instance of any of its descendant classes could not be set to a value outside its intended range. That task is given to you again here.

The solution is to insert a setTo() method that both overrides and calls the method inherited from its grandparent class, Counter.

Option 2: Correcting the problem only in Clock:
Here, the solution is to add code to the set methods in the Clock class so that they test their parameters for validity and throw an IllegalArgumentException if the test fails.


Submission of Work

Submit your Clock source code (i.e., the file Clock.java) to the lab05_dir folder. If, in Step 7, you modified the BoundedCounter class, submit that source code, too.

Sample ClockApp Dialog

Welcome to the Clock application.
Initializing clock...
Enter hour: 5
Enter minute: 9
Enter second: 45

hour: 5; minute: 9; second: 45
24-hour display: 05:09:45
AM/PM display:   5:09:45AM
default display: 05:09:45

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 1

hour: 5; minute: 9; second: 46
24-hour display: 05:09:46
AM/PM display:   5:09:46AM
default display: 05:09:46

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 6
Enter second: 58

hour: 5; minute: 9; second: 58
24-hour display: 05:09:58
AM/PM display:   5:09:58AM
default display: 05:09:58

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 1

hour: 5; minute: 9; second: 59
24-hour display: 05:09:59
AM/PM display:   5:09:59AM
default display: 05:09:59

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 1

hour: 5; minute: 10; second: 0
24-hour display: 05:10:00
AM/PM display:   5:10:00AM
default display: 05:10:00

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 1

hour: 5; minute: 10; second: 1
24-hour display: 05:10:01
AM/PM display:   5:10:01AM
default display: 05:10:01

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 7
Enter hour: 19
Enter minute: 59
Enter second: 59

hour: 19; minute: 59; second: 59
24-hour display: 19:59:59
AM/PM display:   7:59:59PM
default display: 19:59:59

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 1

hour: 20; minute: 0; second: 0
24-hour display: 20:00:00
AM/PM display:   8:00:00PM
default display: 20:00:00

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 3

hour: 20; minute: 0; second: 0
24-hour display: 20:00:00
AM/PM display:   8:00:00PM
default display: 8:00:00PM

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 1

hour: 20; minute: 0; second: 1
24-hour display: 20:00:01
AM/PM display:   8:00:01PM
default display: 8:00:01PM

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 2

hour: 20; minute: 0; second: 1
24-hour display: 20:00:01
AM/PM display:   8:00:01PM
default display: 20:00:01

(1) tick       (2) set to 24-hour mode  (3) set to AM/PM mode
(4) set hour   (5) set minute           (6) set second
(7) set h/m/s  (8) quit
> 8

hour: 20; minute: 0; second: 1
24-hour display: 20:00:01
AM/PM display:   8:00:01PM
default display: 20:00:01

Goodbye.