Using Interface References


The code you implemented in Student uses GradingStrategy as the type for defining both instance variables and parameters:

 public class Student implements Comparable<Student> {    ...    private GradingStrategy gradingStrategy =        new RegularGradingStrategy();    ...    void setGradingStrategy(GradingStrategy gradingStrategy) {       this.gradingStrategy = gradingStrategy;    } 

Even though you create a RegularGradingStrategy object and assign it to the gradingStrategy instance variable, you defined gradingStrategy as being of the type GradingStrategy and not of the type RegularGradingStrategy. Java allows this: A class that implements an interface is of that interface type. A RegularGradingStrategy implements the GradingStrategy interface, so it is a GradingStrategy.

When you assign an object to a reference variable of the GradingStrategy interface type, it is still a RegularGradingStrategy object in memory. The client working with a GradingStrategy reference, however, can send only GradingStrategy messages through that reference.

The code in Student doesn't care whether it is passed a RegularGradingStrategy or an HonorsGradingStrategy. The code in the getGpa method can send the getGradePointsFor message to the gradingStrategy reference without having to know the actual type of the instance stored at that reference.

Always prefer use of an interface type for variables and parameters.


The use of interface types is a cornerstone to implementing systems with good object-oriented design. Interfaces are "walls of abstraction." They allow you to define a means of interacting with an object through an abstractionsomething that is unlikely to change. The alternative is to be dependent on a class with concrete detailssomething that is likely to change.

Why is this important? Because any time you introduce a change to class X, you must recompile and retest all classes that are dependent upon class X. You must also recompile and retest any classes dependent upon those classes. Changes to class X in Figure 5.3 could adversely impact both dependent classes A and B.

Figure 5.3. Changes to X Impact Both A and B


Interfaces invert the dependencies so that client classes are dependent upon abstractions.[5] The class that implements the interface is also dependent upon this abstraction. But the client class is no longer dependent upon the concrete, changing class. In Figure 5.4, the interface XAbstraction represents abstract concepts from XImplementation. Classes A and B now communicate to XImplementation objects via this interface. Classes A and B now are dependent upon abstractions only. The XImplementation class depends upon the abstraction as well. No class in Figure 5.4 depends upon implementation details that are likely to change!

[5] [Martin 2003], p. 127.

Figure 5.4. Inverted Dependencies


When designing object-oriented systems, you want to strive for this dependency arrangement. The more you depend upon concrete types, the more difficult your system is to change. The more you depend upon abstract types (interfaces), the easier your system is to change. By introducing interfaces, you build an abstraction barrier between the client and a concrete server class.



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