CSC148H lab -- week 3


Here are the instructions for the week 3 CSC148H lab. To earn your lab mark, you must actively participate in the lab. As always, you will work as a pair, taking turns being the driver and the navigator. The driver types, and the navigator watches for mistakes, thinking ahead. At the end of each exercise, show your TA what you've done, and then switch roles.

This week's exercises are on the topic of class design and object creation.

Getting started

The first driver should begin by making a new folder "lab3". We suspect that you may be better off just staying in the first driver's account, since a good deal of the work here involves modifying what you've just finished doing.

In the new folder, "lab3", save the file that we've provided for you: Driver.java. You'll see that it allows you to read a sequence of integers from the keyboard and store them in a List.

Exercise 1: Counting passes

Modify the contents of the main() method in the Driver class so that it prints the number of pass marks read from the input. A "pass" is a mark of at least 50. Don't bother checking whether the marks are actually between 0 and 100.

You may want to look at the API documentation for the java.util.List interface, where you can read about the useful methods add(), get() and size(). These make it quite easy to run through all the elements of a list.

Exercise 2: Create a Mark class

Instead of just using Integers to represent marks, we want to have a special class for marks, called (of course) Mark.

Create a new file Mark.java containing a class also called Mark. This class needs these members:

Now modify Driver's main method so that it creates Marks instead of Integers, and uses the isPass() method instead of comparing the mark's value with 50 when it's counting passes.

To get an int to pass to Mark's constructor, you can use Integer.parseInt(), or call the intValue() method of the Integer object already in main().

Exercise 3: Letter grades

Let's allow letter grades. Instead of the full set of A to F with A+, B-, etc., let's just have A, B and F, with corresponding integer marks 90, 75 and 25.

Write a class LetterGrade that is a child class of Mark. You'll need a constructor, LetterGrade(String grade), and you'll also have to override isPass() so that it returns true or false depending on whether the grade is A, B or F. You'll also need to rewrite intValue().

It would be good to have LetterGrade's constructor call Mark's constructor, but that would be a little difficult to arrange. (At-home exercise: try it, and see why it's hard.) In fact, to keep the compiler happy, you're going to have to put this line at the beginning of the constructor for LetterGrade:

super(0);

At this point, you'll need to modify the input loop in main(), because now you need to ask the user whether the mark about to be read is a letter grade or not. Depending on the answer ("y" or "n"), you'll create a Mark as before, or a LetterGrade. But -- and this is a vital point -- the type of the variable (probably named "mark") that refers to the newly-created Mark or LetterGrade object is still Mark. Thus, when you're counting passes in the final part of main(), you can just treat everything as a Mark, because LetterGrade is a child class of Mark.

Just using the class Mark for all the objects when you're counting passes is an application of polymorphism.

Exercise 4: A better class design

What we got from Exercise 3 was a program with inheritance, but we also got a class structure with, to be blunt, a bad design. Our program looks as if a LetterGrade is a kind of Mark, but really a (numeric) Mark and a LetterGrade are two different kinds of mark that should have equal status. In our last exercise, we'll create a parent class Mark with two child classes, NumericGrade and LetterGrade.

First, copy your existing Mark.java to NumericGrade.java. Now,

  1. Edit NumericGrade.java so that its class is also called NumericGrade and is a child of (extends) Mark. Be sure to change the constructor's name, too.
  2. Edit Mark.java by removing the constructor and the instance variable value. Make isPass() return true all the time, and make intValue() return -9999. (These are silly values, but they're the best we can do here.) Those two methods are all that's left of the Mark class.
  3. You can get rid of "super(0);" in the constructor for LetterGrade, too.
  4. Edit Driver.java so that when it's creating a numerical grade, it actually uses NumericGrade.

And finally:

  1. Remove the method isPass() from both LetterGrade and NumericGrade. Make sure they both have a valid intValue().
  2. Change isPass() in Mark so that it does this, and only this:
    return intValue() >= 50;
    

Your program should now compile and run successfully. If so, ...

Congratulations! You've built a program that uses inheritance, overriding, and polymorphism -- all vital parts of object-oriented design. There are still things to learn; for example, the program could be improved by the use of abstract classes, and we would dearly love to assign you the task of building your own PassFailGrade class. But the essentials are all there.