Refactoring


Time to eliminate the duplicate code you hastily introduced.

The only change between getEndDate as defined in CourseSession and SummerCourseSession is the session length. Define a protected method in CourseSession to return this value:

 public class CourseSession implements Comparable<CourseSession> {    ...    protected int getSessionLength() {       return 16;    }    ... 

Change getEndDate to call getSessionLength:

 public Date getEndDate() {    GregorianCalendar calendar = new GregorianCalendar();    calendar.setTime(getStartDate());    final int daysInWeek = 7;    final int daysFromFridayToMonday = 3;    int numberOfDays =       getSessionLength() * daysInWeek - daysFromFridayToMonday;    calendar.add(Calendar.DAY_OF_YEAR, numberOfDays);    return calendar.getTime(); } 

In SummerCourseSession, override the method getSessionLength. Summer sessions are 8 weeks, not 16. In this case, overriding is a fine alternative to extending, since you are not changing behavior, only data-related details of the behavior.

 public class SummerCourseSession extends CourseSession {   ...    @Override    protected int getSessionLength() {       return 8;    }    ... 

When you override a method, you should precede it with an @Override annotation. You use annotations to mark, or annotate, specific portions of code. Other tools, such as compilers, IDEs, and testing tools, can read and interpret these annotations. The Java compiler is the tool that reads the @Override annotation.

The compiler ensures that for a method marked as @Override, a method with the same name and arguments exists in a superclass. If you screwed up somehowperhaps you mistyped the method as getSessionLentgh instead of getSessionLengththe compile fails. You see the message:

 method does not override a method from its superclass 

Java does not require you to add @Override annotations to your code. However, they provide valuable documentation for your code as well as protections from simple mistakes. You can read more about annotations in Lesson 15.

You may now remove getEndDate from SummerCourseSession. In Figure 6.3, the getSessionLength operation appears twice, an indication that the subclass (SummerCourseSession) overrides the superclass (CourseSession) definition. Note that I have preceded each method with access privilege information, something I rarely do. Since normally I only display public information in a UML sketch, I prefer to omit the + (plus sign) that indicates a publicly accessible operation.

Figure 6.3. Overriding a Protected Method


In this circumstance, however, getSessionLength is protected, not public. Adding the access privilege indicators to the diagram in Figure 6. differentiates access between the methods and highlights the relevancy of getSessionLength. The UML indicator for protected is the pound sign (#).[3]

[3] The UML access indicator for private is (-). The indicator for package-level access is (~).

Idiosyncrasies

Since Java does not require you to add @Override annotations to methods, it's easy to forget. (That's one thing a pair developer can be good for.) The @Override annotation is a new J2SE 5.0 feature, so I have my excuse if I've forgotten to use it elsewhere in Agile Java.

You'll note that I do not use @Override on my setUp and tearDown methods, even though the annotation is applicable for these TestCase method overrides. Using @Override would be a good idea (particularly since it's easy enough to spell setUp as setup). But old habits are hard to break. I justify it by saying that it's only test code and the tests will help correct me anyway. Nonetheless, I recommend that you avoid my bad habits.


Most of the logic for determining the end date of a session is fixed. The only variance in the logic between CourseSession and SummerCourseSession is the session length. This variance is represented by the abstraction of a separate method, getSessionLength. The CourseSession class can supply one implementation for getSessionLength, the SummerCourseSession another.

The method getEndDate in CourseSession acts as a template. It supplies the bulk of the algorithm for calculating a session end date. Certain pieces of the algorithm are "pluggable," meaning that the details are provided elsewhere. Subclasses can vary these details. The template algorithm in getEndDate is an example of a design pattern known as Template Method.[4]

[4] [Gamma1995].



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net