- CourseSession
- Enrolling Students
- int
- Initialization
- Default Constructors
- Suites
- The SDK and java.util.ArrayList
- Adding Objects
- Incremental Refactoring
- Objects in Memory
- Packages and the import Statement
- The java.lang Package
- The Default Package and the package Statement
- The setUp Method
- More Refactoring
- Class Constants
- Dates
- Overloaded Constructors
- Deprecation Warnings
- Refactoring
- Creating Dates with Calendar
- Comments
- Javadoc Comments
- Exercises
Refactoring
A quick improvement is to remove the unnecessary local variable, endDate, that appears at the end of the method getEndDate in CourseSession. Declaring the temporary variable aided in your understanding of the Calendar class:
Date endDate = calendar.getTime(); return endDate;
A more concise form is to simply return the Date object returned by the call to getTime.
return calendar.getTime();
Import Refactorings
The CourseSession class now must import four different classes from the package java.util:
import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; import java.util.Calendar;
This is still reasonable, but you can see that the list could quickly get out of hand as more system library classes are used. It is also a form of duplication—the package name is duplicated in each import statement. Remember that your primary refactoring job is to eliminate as much duplication as possible.
Java provides a shortcut version of the import statement to declare that you are importing all classes from a specified package:
import java.util.*;
This form of import is known as a package import. The asterisk (*) acts as a wildcard character.
After making this change, you can use any additional classes from the java.util package without having to modify or add to the import statements. Note that there is no runtime penalty for using either this form or the singular class form of the import statement. An import statement merely declares that classes might be used in the class file. An import statement does not guarantee that any classes from a package are used in the class file.
There is no consensus about which form is more proper. Most shops use the * form of the import statement either all the time or when the number of import statements begins to get unwieldy. Some shops insist that all classes must be explicitly named in the import statements, which makes it easier to determine the package a class comes from. Modern Java IDEs can enforce the import convention your shop decides on and even switch back and forth between the various forms. An IDE makes the choice of which form to use less significant.
It is possible to import a class or package but not use the class or any classes from the package within your source code. The Java compiler will not warn you about these unnecessary import statements. Most modern IDEs have optimizing facilities that will help you remove them.
Improving Understanding with a Factory Method
The getEndDate method in CourseSession is the most complex method you've written yet. It's about as long as you want your methods to get. Most of the methods you write should be between one and half a dozen lines. Some methods might be between half a dozen and a dozen or so lines. If your methods are regularly this length or even longer, you should work on refactoring them. The primary goal is to ensure that methods can be rapidly understood and maintained.
If your methods are short enough, it will be easy to provide a meaningful, concise name for them. If you are finding it difficult to name a method, consider breaking it up into smaller methods, each of which does only one succinctly nameable thing.
Another bit of duplication and lack of clarity that you should be unhappy with lies in the test method. For the time being, you are using the deprecated Date constructors, a technique that is considerably simpler than using the Calendar class. However, the code is somewhat confusing because the year has to be specified as relative to 1900, and the months have been numbered from 0 through 11 instead of 1 through 12.
In CourseSessionTest, code a new method called createDate that takes more sensible inputs.
Date createDate(int year, int month, int date) { return new Date(year - 1900, month - 1, date); }
This will allow you to create dates using a 4-digit year and a number from 1 through 12 for the month.
You can now refactor setUp and testCourseDates to use this utility method. With the introduction of the utility method, defining the local variables year, month, and date adds little to the understanding of the code, since the factory method [8] createDate encapsulates some of the confusion. You can eliminate the local variables and embed them directly as parameters in the message send to createDate:
public void setUp() { startDate = createDate(2003, 1, 6); session = new CourseSession("ENGL", "101", startDate); } ... public void testCourseDates() { Date sixteenWeeksOut = createDate(2003, 4, 25); assertEquals(sixteenWeeksOut, session.getEndDate()); }
Some of you may be shaking your head at this point. You have done a lot of work, such as introducing local variables, and then you have undone much of that same work shortly thereafter.
Part of crafting software is understanding that code is a very malleable form. The best thing you can do is get into the mindset that you are a sculptor of code, shaping and molding it into a better form at all times. Once in a while, you'll add a flourish to make something in the code stand out. Later, you may find that the modification is really sticking out like a sore thumb, asking for someone to soothe it with a better solution. You will learn to recognize these trouble spots in your code ("code smells," as Martin Fowler calls them.) [9]
You will also learn that it is cheaper to fix code problems now rather than wait until the code is too intertwined with the rest of the system. It doesn't take long!
Keep your code clean at all times! |