for the class to compile. We could, of course, have included everything in the statistics pack-
age by replacing the import with:
But that would have included more than what is used in the BatterImpl class. I find it good
practice to include only those parts of a package that are necessary. If nothing else, too long
a list of imports from another package shows an interconnection between the package being
imported and the package doing the importing that might indicate a design flaw. If you have
to import too much from a different package, you have a lot of dependencies between them,
and your package abstractions may not be correct.
The number of places that may have to be changed can get out of hand rather rapidly, es-
pecially if you are doing this kind of refactoring over a large code base. Fortunately, most
modern interactive development environments (in particular, both Eclipse and Netbeans) have
very good facilities that automate all or nearly all of the changes required for this kind of re-
factoring. This is one of the places where a good IDE really shines, although traditionalists
will also be able to accomplish the same sort of thing with scripts.
An interesting question in this refactoring is where to put our exception class,
NotEnoughAtBatsException . This is a class, as are all exceptions, and so would generally
be part of the package that contains implementations. This would argue for placing it in the
com.oreilly.javaGoodParts.examples.impl package, but the definition of the Batter in-
terface in the com.oreilly.javaGoodParts.examples.statistics package refers to this
exception. So our choice is either to import the exception from the implementation package
into the interface package or to include a particular implementation in our set of interfaces.
Neither of these choices is particularly clean. The purpose of defining a set of interfaces is
to allow those interfaces to be independent of the implementation classes. Importing an ex-
ception class from an implementation package explicitly ties the interface to at least part of
a particular implementation. But including the exception in the interface package means that
the particular implementation of the exception is part of the abstract definition of the set of
interfaces, which I have argued in Chapter 2 is a bad idea.
The real cause of this problem is that exceptions in Java cannot be defined as interfaces and
can be defined only as extensions of the Exception class. Since we want to declare exceptions
as part of the signature of methods that are first defined in interfaces, there is no way of avoid-