Guided Task: Extract a Super Class
With the new hierarchy design, now you need to move toward implementation. The common elements are already implemented in Course. You can extract those elements into the parent class. Attempting this extraction manually can be messy and can lead to breaking the code. Luckily, Eclipse provides a refactoring tool that helps with extracting a super class, because developers frequently need to make these types of changes in their code.
Extract the Super Class
To extract the Activity super class, do the following:
- Open
Coursein the editor. - Right click in the
Courseclass in the editor and select Refactor > Extract Superclass. Make sure you are in the curly braces (e.g.,{}) that defineCourse, otherwise the option to Extract Superclass won’t be available! - Give the superclass the name
Activity. - Select the checkboxes next to the following members of
CourseUPPER_HOURUPPER_MINtitlemeetingDaysstartTimeendTimegetTitle()setTitle()getMeetingDays()getMeetingString()getStartTime()getEndTime()setMeetingDaysAndTime()- Any private helper methods that you wrote to support the implementation of the above methods (the teaching staff solution has a helper method
getTimeString())
- Click Next and verify that you have all the items you need.
- Click Next. Eclipse will provide a warning that the visibility of the method
getTimeString()will change due to the refactoring. Since the method is used inCourse, the method will need to be public soCoursecan access it. Warnings like this should be noted for review after the refactoring.
- Click Next again. You’ll see a list of the changes that will be performed as part of the refactoring.
- Click Finish.
Check Compilation
Your code won’t compile after the extraction of the super class. You will have compiler errors in Course and CourseTest. These compilation errors are due to missing parameters when working with methods that were extracted to Activity. The extraction added an extra Course parameter to these methods. They aren’t needed, so let’s remove them.
For example, the method header of Activity.setTitle() should be updated to the following:
1
2
//Remove the Course course parameter
public void setTitle(String title) {
And Activity.setMeetingDaysAndTime() should be updated to the following:
1
2
//Remove the Course course parameter
public void setMeetingDaysAndTime(String meetingDays, int startTime, int endTime) {
The remaining compilation errors in CourseTest are due to the refactoring adding a Course reference to method calls for setTitle() and setMeetingDaysAndTime(). Remove those extra references. Everything should compile.
What Happens if Everything is a Mess After Trying this Refactoring?
First, don’t panic. We’ve provided the correct code for Activity and Course at this step of the Guided Project.
You can replace any of the provided method’s implementations with your own.
Run Tests
Run all of your unit tests on the refactored code. Ensure there are no regressions in functionality.
Update Activity and Course
Now that we have extracted the Activity class, we have a few changes that we need to make to ensure encapsulation of Activity information and provide the additional functionality that Activity needs. Complete the following steps.
Make Activity Abstract
Since Activity is a super class of Course and will soon be the super class of Event, there is no need for Activity to be a concrete class. Instead, Activity should be abstract - that means you cannot directly construct Activity objects. Additionally, we’ll be creating some abstract behavior that we Course and Event will define for their contexts.
- Add the
abstractkeyword to theActivityclass header.
1
2
3
public abstract class Activity {
...
}
Make Activity’s Fields Private
When creating the super class, Eclipse set the fields of Activity to protected level access. This means that any sub-class can access the fields directly. However, it also means that another class in the same package can also access the fields directly. To protect your fields, make them private.
Resolve Course Compilation Errors
There will be several compilation errors in Course after you make the fields in Activity private in the hashCode(), equals(), and toString() methods. Do the following to resolve:
- Remove
hashCode()andequals(). Now that there is a super class, you should regeneratehashCode()andequals()to use the super class. DO NOT do generate a newequals()andhashCode()yet! - In
toString(), change direct references toActivityfields to use the associated getter methods.
- Run your tests. The tests for
Course.hashCode()andCourse.equals()will fail. TheWolfSchedulerTest.testGetCourseFromCatalog()will also fail becauseCourse.equals()is not yet reimplemented. You’ll fix those shortly!
Create Activity’s Constructor
Activity was created with a parameterless constructor. You want to continue to use the one path of construction paradigm. That means you need a way to construct Activity and its fields.
- Replace the default
Activityconstructor with one that requires all of the fields. The parameters MUST be in the order oftitle,meetingDays,startTime, andendTime. Additionally, update the body of the constructor to use the appropriate setter methods for the fields since all of the error checking is completed there.
1
2
3
4
5
public Activity(String title, String meetingDays, int startTime, int endTime) {
super();
setTitle(title);
setMeetingDaysAndTime(meetingDays, startTime, endTime);
}
Update Course Constructor
After you add a parameterized constructor to Activity, Course no longer compiles. Now, Course needs to call the parameterized Activity constructor.
- Update
Course’s non-compiling constructor to useActivity’s new constructor. Remember,Activityis the parent ofCourse. To interact with the parent class, you need to use thesuperreference.
1
2
3
4
5
6
7
8
9
10
public Course(String name, String title, String section, int credits, String instructorId, String meetingDays,
int startTime, int endTime) {
super(title, meetingDays, startTime, endTime);
setName(name);
//setTitle(title); <-- DELETE THIS, called in super
setSection(section);
setCredits(credits);
setInstructorId(instructorId);
//setMeetingDaysAndTime(meetingDays, startTime, endTime); <-- DELETE THIS, called in super
}
- Run your unit tests to make sure that everything is still passing (except for the failures discussed above).
Generate hashCode() and equals()
Do the following to add back the hashCode() and equals() functionality in both Activity and Course. Note that you want to generate Activity’s methods first since Course’s method will rely on Activity’s.
- Use Eclipse’s source generation tools to generate
hashCode()andequals()inActivity. - Then use Eclipse’s source generation tools to generate
hashCode()andequals()inCourse. - Run your unit tests. They should all be passing again!
Add Abstract Functionality to Activity
Adding events will complicate the display of information in the GUI. There will be some items that Course has that Event will not and vice versa. Creating the array of Strings for display in the GUI should instead be delegated to classes in the Activity hierarchy. You will add two abstract methods that will provide a short and a long version of the array of information to provide to the GUI.
- Add the statement
public abstract String[] getShortDisplayArray();toActivity. - Add the statement
public abstract String[] getLongDisplayArray();toActivity.
After adding the methods, make sure you comment them. This will help any developers that extend Activity in the future better understand the intention of the methods. The short display array is used to populate the rows of the course catalog and student schedule [UC1, UC3, UC4, UC6]. The full display array is used to display the final schedule [UC9].
Implement Abstract Functionality in Course
After you add these statements, Course will no longer compile. Select the compiler error on the Course class header and use the Quick Fix to add implementations of these two methods to Course.
Implement the methods in Course as follows:
getShortDisplayArray()returns an array of length 4 containing theCoursename,section,title, and meeting string.getLongDisplayArray()returns an array of length 7 containing theCoursename,section,title,credits,instructorId, meeting string, empty string (for a field thatEventwill have thatCoursedoes not).
Extended Course Unit Testing
Using the WolfScheduler requirements along with the provided ExtendedCourseTest JUnit tests, you will finish implementing the Course class to pass the tests!
Download the provided ExtendedCourseTest JUnit tests and put it in the edu.ncsu.csc216.wolf_scheduler.course package in the test/ folder. If you do this via the file system, right click on the project in Eclipse and refresh so the test file is recognized by Eclipse. You can now run the tests. Fix any failures.
Keep Both Test Files
Keep both CourseTest.java and ExtendedCourseTest.java in your project. CourseTest contains the original GP1 tests that verify basic Course functionality, while ExtendedCourseTest contains additional tests for the new Activity hierarchy features (like getShortDisplayArray() and getLongDisplayArray()). Both test files should pass when you submit.
Comment Activity and Course and Fix Static Analysis Notifications
Update all your Javadoc for Activity and Course. Make sure you update all references to Course in the comments for Activity.
Overridden methods much also be commented to describe the specifics in the overridden implementation. Note that Checkstyle will NOT generate notifications if you’re missing comments on overriden methods. But we do check for that when grading!
Now is a great time to make sure that CheckStyle, PMD, and SpotBugs are all active on your project. Right click on the WolfScheduler project and select Properties. You can select each tool and make sure it is turned on. Resolve all the notifications.
GitHub Resources:
Check Your Progress
Complete the following tasks before pushing your work to GitHub.
- Make sure that all fields, methods, and constructors are commented.
- Resolve all static analysis notifications.
- Fix test failures.
- Commit and push your code changes with a meaningful commit message. Label your commit with “[Refactoring]” for future you!
