CSE 131 Module 7: Objects


Object Design and Encapsulation

Your task is to generate two classes: Student and Course using a test-driven development approach. This means that your goal is to get the unit tests to pass, and you develop your code incrementally to get more of the tests to pass.

First, take a look at the StudentAndCourseTest.java file. In that file you will see unit tests. Unfortunately, none of the tests will currently pass. You use these tests as you develop your classes to verify whether they are working as intended. You are also encouraged to write some additional tests of your own. Be sure to test often!

Creating a Student class

  1. Create a new Student class in the lab7 package of your labs folder.
    You do not need to check the box that generates the main method. We won't be running your Student class directly, but instead testing its functionality via the unit test.

    It is important as you work on this lab that you do not change the existing tests in StudentAndCourseTest. You may add tests, but the existing tests must be preserved.

    We will test your code after you commit and push to make sure it passes the tests as given, and credit may be revoked if you do not pass the given tests!

  2. Start crafting a Student class. Students have lots of wonderful properties, but we are primarily interested in these:

    Add these properties as instance variables to your class, create a constructor, create some getters and setters, and test!

    How do you know what to name your instance variables? How do you name the getters and setters? Good questions, and this relates to encapsulation.

    Your instance variables can, should, and must be declared private. In this way, their names are not exposed outside the Student class, which protects them from unintended access. More on this as you read further.

    On the other hand, the getters and setters may be referenced by the unit test. The names and type signatures of your method must conform to their use in the unit test. For example, the testStudentInit method in StudentAndCourseTest contains the constructor call:

    Student s = new Student("Doug", "Shook", 111111)
    From this line we can reason that the constructor takes in a String, another String, and an int. We can also reason that the first parameter of the constructor is the student's first name, and the second parameter is the student's last name.

    You can similarly read the test code in StudentAndCourseTest to see how the getters and setters are named.

    We now pause for a teaching moment. Why the fuss about encapsulation?
    • Suppose you wanted to count the number of times a student's ID is accessed. If the instance variable is public, then access to the variable's value can occur in any other class, beyond the view of the Student class. By making the instance variable private, and requiring a getter to access the value, the Student class can count the number of accesses to the value.
    • Suppose you wanted for some reason to change the representation of a student's ID from an integer to a string, or suppose you really want to change the name of the instance variable. If you made the variable public, then other code may subsequently be written that requires the name and type of the instance variable to stay the same.

      By making the instance variable private, you encapsulate it within the Student class and you have control therefore over that instance variable's future.

    • Suppose you decide that a student's ID should not be a settable property of a Student, by any code outside the Student class. If you make the instance variable public, code outside of the Student class can read or write the instance variable. Only by making the variable private can you arrange for the value to be manipulable within the Student class, but not outside of that class.

    Encapsulation allows us to retain control over some aspects of a class's specification, while releasing only those portions that are necessary by design.

    This point is emphasized below when we ask you to consider computing the worry factor of a Student.

  3. At this point, the testStudentInit test case should pass when you run StudentAndCourseTest as a jUnit test.
  4. Now we want to add some functionality to our Student class. Add the following methods:

    Recall the has-a concept presented in the course videos. As you read through the methods below and consider their implementation, you may develop a feeling that your class should have something it does not yet have. Feel empowered to introduce other instance variables as necessary. Remember that they too deserve nice names, they should be initialized in your constructor(s), but they do not need (nor should they have) getters or setters. They are used to manage data within your class.
    void submitGrade(??? grade, int credits)
    This method takes in a course grade (as a value between 0 and 4) and the number of credits for a course, and updates the students GPA as described below.
    But first, what about those ??? marks in the type for grade? You must figure out the type for grade by looking into the unit test and seeing what kind of values are supplied for that parameter. The grade could be an int or a double, so only the unit test can show you what is needed.

    A helpful hint: if you pause your mouse over a variable, eclipse will tell you the type of that variable. I know, right? Too good to be true.

    GPA can be computed by the following formula:

    Take the number of credits for a course and multiply it by the grade for that course. This is called the quality score. GPA is computed as the sum of all of the quality scores for each course the student has taken, divided by the total number of credits.

    You must also round the GPA so that it only contains three digits after the decimal.

    Run the unit test again, and at this point both testStudentInit and testSubmitGrade should pass.
    String getClassStanding()
    returns the students class standing based on how many credits they have:

    Fewer than 30 "FirstYear"
    30 or more but fewer than 60 "Sophomore"
    60 or more but fewer than 90 "Junior"
    90 or more "Senior"
    What should you do now? Oh you already know: run the unit test again.
    At this point, which tests should be passing?
    Student createLegacy(Student otherParent)
    It is not unusual for two students to meet at college, start a family, and send their children to the same school. This method should take a Student object as a parameter and then create and return a new Student object as described below. There are three particpants in this method:
    • one parent,
    • the other parent, and
    • the child Student that is created and returned by the method.
    Wait, how can there be two parents for createLegacy when the method has just one parameter: otherParent?

    You must remember that every non-static method in an object has access to this: the object (often called the receiver) upon which the method was called. So, if the code a.createLegacy(b) is executed, then within createLegacy, object a is bound to this, and object b is bound to otherParent.

    Thus, createLegacy has access to two Student objects, this and otherParent, and you are asked to consider each of those as a parent of the new Student object that will be returned by this method.

    Here is what this method must do:
    • Use one parent's full name as the baby's first name, the other parent's full name as the baby's last name
    • Assign the baby a student ID that is the sum of its parents' IDs.
    • The legacy's initial GPA will be returned as the average of its parents' GPA.
    • The legacy's initial number of credits will be the maximum of its parents' credits

    Hint: it may be useful to create an additional constructor!

    The reason is that the constructor you already have sets the GPA and such to 0, but for this method, you need to construct a student with an existing GPA.

    This new constructor should be private, not public. Do you see why?

    Can you arrange for the previous, public constructor to call this new private one via this(…)? This idea is covered in the videos but here are some extra resources:

    String toString()
    returns the students full name and student ID
  5. Before moving on, make sure that all of the tests for the Student pass! There are other tests in StudentAndCourseTest (for the Course class that you develop below) that won't pass yet.

  6. Now go back and think again about the instance variables of this class and their getters and setters. Which of the instance variables should have getters, and which should have setters?
    To reason about this, you need to think about what the unit test is doing, and you must provide getters or setters so that it can work. But beyond that, think about how this class will be used.
    • Should the student ID have a setter? That is, do we want to provision for the student ID of a Student object to change? What does the initial story of a Student object say about that?
    • How about the name? Washington University allows students to change their names.
    • Should the number of credits be settable directly outside the class? Or should access be more carefully controlled?

    The TAs will discuss this with you when you demo.

  7. Extra fun, and related to the discussion about about encapsulation. Suppose we want to compute the worry factor of a Student, defined as the number of times getGPA() is called between calls to submitGrade(…).
    You will get credit for this lab without implementing the above idea, but your instructors consider it fair game to place such a question on an exam.

Creating a Course class

You had some guidance above in consulting the StudentAndCourseTest unit test to drive the creation of the Student class. Here we give you less guidance, but use the same approach to develop the Course class.

The Course class should contain the following properties:

  1. Add these properties as instance variables to your class, create a constructor, create some getters and setters, and test!

    As before drive your software development by the unit test.

    Avoid creating extra functionality that is not demanded by the unit test or specifically required in this document. This approach saves you time and keeps the resulting code simple.

  2. Next, implement the following functionality:

    boolean addStudent(Student s)
    Check to make sure that the student has not already enrolled, and update the number of seats remaining. Return true if s has been enrolled as a result of this call. Return false otherwise.
    How will you check that the student has not already enrolled? You'll have to keep track of the students as they enroll. Fortunately, when a Course object is constructed, we know the maximum number of seats that the course offers, so we know the maximum number of enrolled students.

    From what we have studied, what is the appropriate data type to keep track of enrolled Students in a Course?

    String generateRoster()
    returns a String that represents a roster with all of the Students in the course. The roster should contain the Students' names. Make sure to omit empty seats!
    double averageGPA()
    returns the average GPA of all students enrolled in the course. Make sure to omit seats! from this calculation
    String toString()
    the returned String should contain the course number and credits

Submitting your work (read carefully)

Last modified 12:48:23 CDT 30 August 2017
When you done with this lab, you must be cleared by the TA to receive credit.

This demo box is for lab 7
Last name WUSTL Key Propagate?
(NOT your numeric ID) Do not propagate
lower case only
e.g. Smith j.smith

Acknowledgements and assertion of integrity

You must select one of the options below
The work submitted here was performed in accordance with this course's policy on collaboration.
On your honor, you have neither given nor received any unauthorized aid on this assignment.

However, the following TAs, students, or professors were supportive in completing this assignment.
Their help was also in accordance with course policies.

Thanks to (leave blank if appropriate):

In spite of seeking help as allowable by this course's policy on collaboration, you were unable to complete this assignment. No credit will be received for this assignment.

You would like to be contacted by an instructor to facilitate staying on track in this course.

Comments about this:

You have NOT abided by this course's policy on collaboration. No credit will be received for this assignment, but by checking this box, no academic integrity violation will be filed for this assignment.

You would like to be contacted by an intructor to faciliate staying on track in this course.

Comments about this:

TA: Password: