My favorites | Sign in
Google
                
Search
for
Updated Aug 07, 2009 by ffaber
KeepConstructorsHidden  

Keep constructors on Guice-instantiated classes as hidden as possible.

Consider this simple interface:

public interface DataReader {
 
  Data readData(DataSource dataSource);
}

It's a common reflex to implement this interface with a public class:

public class DatabaseDataReader implements DataReader {
  
   private final ConnectionManager connectionManager;

   @Inject
   public DatabaseDataReader(
      ConnectionManager connectionManager) {
     this.connectionManager = connectionManager;
   }

   @Override
   public Data readData(DataSource dataSource) {
      // ... read data from the database
      return Data.of(readInData, someMetaData);
   }
}

A quick inspection of this code reveals nothing faulty about this implementation. Unfortunately, such an inspection excludes the dimension of time and the inevitability of an unguarded code base to become more tightly coupled within itself over time.

Similar to the old axiom, Nothing good happens after midnight, we also know that Nothing good happens after making a constructor public: A public constructor will have illicit uses introduced within a code base. These uses necessarily will:

  • make refactoring more difficult.
  • break the interface-implementation abstraction barrier.
  • introduce tighter coupling within a codebase.

Perhaps worst of all, any direct use of a constructor circumvents Guice's object instantiation.

As a correction, simply limit the visibility of both your implementation classes, and their constructors. Typically package private is preferred for both, as this facilitates:

  • binding the class within a Module in the same package
  • unit testing the class through means of direct instantiation

As a simple, mnemonic remember that public and @Inject are like Elves and Dwarfs: they can work together, but in an ideal world, they would coexist independently.


Comment by kwhittingham, Aug 08, 2009

You tell us what not to do but not what we should do? Private class? Private ctors?

Comment by dhanji, Aug 08, 2009

Package local/private class is my preference. Or the same for (or protected) constructor depending on your use case. A lot of this depends on how the specific class in intended to be used.

The doc's main point is, prefer depending on interfaces and let Guice call new, as this gives you the maximum amount of control and flexibility of design.


Sign in to add a comment