Saturday, March 26, 2011

Immutability and builders

Once you get to a certain point in working with Java, you always keep in mind how your code will work in a multi-threaded environment. It isn't a strange thing to think about: servlets run with threads, as do EJBs and Swing applications. Even if you are not dealing with threads now, you could be in the future, or someone else might try to apply your code to threads.

One of the easiest ways to handle the question "Will this work with threads?" is to make your classes immutable. The state of an immutable object cannot be changed after its construction. If an object is immutable, then there is no chance that threads will see different state in the object when they shouldn't. Immutability also leads to a simpler API for your class and overall more predictable behavior.

Here's a typical immutable class.
public class USAddress {
  private final String streetAddress;
  private final String city;
  private final String state;

  public USAddress (String a, String c, String s) {
    streetAddress = a;
    city = c;
    state = s;
  }
  public String getStreetAddress() { return streetAddress; }
  public String getCity() { return city; }
  public String getState() { return state; }
The fields in this class are all final, which means two things: first, that they can only be assigned once; second, that they must be assigned after construction. These properties of final help make the class immutable.

I didn't include implementations of equals() or hashCode(), but I'll just say that they would depend on the fields in the class. Immutability implies that the hash code of a USAddress object never changes, which is great because it will never get lost in a hash table. For some objects, if there are a lot of computations involved for generating a hash code, you could just calculate it once and cache it internally for speed.

One downside to immutable classes is that they must have all their data passed to them on construction. Let's expand the class above and see what happens. I'm going to leave out the getter methods.
public class USAddress {
  private final String streetAddressLine1;
  private final String streetAddressLine2;
  private final String city;
  private final String state;
  private final String zipCode;
  private final boolean isPostOfficeBox;
  private final boolean isAptOrCondo;

  public USAddress (String a1, String a2, String c, String s, String z,
      boolean p, boolean ac) {
    streetAddressLine1 = a1;
    streetAddressLine2 = a2;
    city = c;
    state = s;
    zipCode = z;
    isPostOfficeBox = p;
    isAptOrCondo = ac;
  }
  // ... getters ...
}
The problem is the constructor. It has five strings in a row and then two booleans in a row. It could be tricky to remember the right order of the parameters, which one is which.
USAddress a = new USAddress ("1234 Elm Street", "Apt. 56",
    "Springfield", "MA", "01103", false, true);
Quick, what do the two booleans mean again?

So you can imagine that some classes can have even more fields, with a variety of types, and working with their constructors gets ridiculous. Fortunately, there is a design pattern that can help you out: the Builder pattern.

A builder is a class that builds another class. You use it instead of directly calling a constructor. Here is a builder example.
public class USAddressBuilder {
  final String streetAddressLine1;
  String streetAddressLine2 = null;
  final String city;
  final String state;
  String zipCode = null;
  boolean isPostOfficeBox = false;
  boolean isAptOrCondo = false;

  public USAddressBuilder (String a, String c, String s) {
    if (a == null) {
      throw new IllegalArgumentException ("null street address");
    }
    if (c == null) {
      throw new IllegalArgumentException ("null city");
    }
    if (s == null) {
      throw new IllegalArgumentException ("null state");
    }
    this.streetAddressLine1 = a;
    this.city = c;
    this.state = s;
  }
  public USAddressBuilder streetAddressLine2 (String a) {
    this.streetAddressLine2 = a; return this;
  }
  public USAddressBuilder zipCode (String z) {
    this.zipCode = z; return this;
  }
  public USAddressBuilder isPostOfficeBox (boolean p) {
    this.isPostOfficeBox = p; return this;
  }
  public USAddressBuilder isAptOrCondo (boolean ac) {
    this.isAptOrCondo = ac; return this;
  }

  public USAddress build() {
    return new USAddress (this);
  }
}
Let's tear this one down.
  • This builder has the same fields as the class it builds. Some of the fields—those that are required—are final, but the optional ones aren't. The optional ones even get default values.
  • The builder's constructor only takes in the fields that are required.
  • To set the optional fields, you call specific builder methods for them. These methods return the builder again, so you can chain calls together (see below).
  • The build() method constructs a USAddress object from the builder data. The constructor (not shown) simply copies the builder fields into the object.
Here's how the builder is used.
USAddress a =
    new USAddressBuilder ("1234 Elm St.", "Springfield", "MA")
    .streetAddressLine2 ("Apt. 56").zipCode ("01103")
    .isAptOrCondo (true).build();
This code is longer, but it's much easier to read. Other nice things you get:
  • You can leave out fields that aren't important (like isPostOfficeBox).
  • The logic for constructing the class is mostly moved over to the builder. This is nice for classes that have lots of other stuff in them.
  • The builder has the option of reusing objects that it already constructed. If you ask for an object with the same data, and those objects are immutable, you could just as well use a copy made earlier. This can save on memory usage. (For more, check out another design pattern, Flyweight.)
  • The builder has the option of sending back a subclass instance. Imagine an AddressBuilder that returns Address objects; if you use a builder and pass in US-style address information, the builder can send you back a specific subclass of Address that specializes in US address data.
There are some downsides.
  • You have to write a lot more code to implement this builder. It's a sacrifice you have to make for easier use later on.
  • It's another class. You can mitigate this downside a little by making the builder an inner class of what it builds (which is what I usually do).
  • Some libraries and frameworks can only use constructors for your classes. I see this more as a problem on their end and not a fault of this pattern, but it's a practical consideration. You might have to make allowances to work within the constraints imposed on you.

Monday, March 14, 2011

Using Guice for dependency injection

So last time I described what dependency injection is. In this post I'll run quickly through how you can use a dependency injection framework. I'm going to pick Guice since I'm familiar with it, and because it's really straightforward.

You instruct Guice on how to do injection using a "module".
public class FlamingoModule extends AbstractModule {
  @Override protected void configure() {
    bind (RouletteBall.class);
    bind (RouletteTable.class);
    bind (Integer.TYPE).annotatedWith (SeatsPerTable.class)
      .toInstance (8);
    bind (SpecialtyDrink.class).to (Margarita.class);
  }
  @Provides RouletteWheel provideRouletteWheel (RouletteBall ball) {
    return new RouletteWheel (ball, true);
  }
}
This module's configure() method sets up some bindings, which is how Guice gets from what you ask it for to what it gives you. The first two bindings just make Guice aware of the RouletteBall and RouletteTable classes. The last one tells Guice that whenever someone asks for a SpecialtyDrink from Guice, it should deliver an instance of the Margarita class.

The third binding tells Guice that whenever it's asked for an integer annotated with @SeatsPerTable, it should send back the value 8. Annotations are a way that you can have Guice inject different values for the same type. Generally you need to code up the annotations yourself.

The provideRouletteWheel() method illustrates a different way Guice can get you objects. When Guice is asked for a RouletteWheel instance, it will run the "provider" method to create one. Guice handles injecting a RouletteBall instance into the method's ball parameter.

In order to finish wiring up the code, we'll need to use the @Inject annotation. This tells Guice to inject a dependency. So, the RouletteTable constructor needs a little work.
@Inject public RouletteTable (RouletteWheel w,
                              @SeatsPerTable int n) {
  numberOfSeats = n;
  wheel = w;
}
Now, when Guice needs a RouletteTable, it knows about it (from the module) and knows to inject values into its constructor. The third binding in the module's configure() method lets it inject n, and the provider method takes care of w. Since Guice also knows about RouletteBall, it can inject an instance of that class into the provider method.

To finally tie it all together, you need a starting point, something that lets you talk to Guice. That's called an injector.
Injector injector = Guice.createInjector (new FlamingoModule());
RouletteTable t = injector.getInstance (RouletteTable.class);
You can see that I could define a new module for a different casino, say, one that uses European roulette wheels and seats ten per table, and use that module with Guice to get a differently constructed RouletteTable object. The knowledge of how to create objects is wrapped up nicely in the modules and doesn't interfere with the use of the objects.

So, after all this, you may wonder why this is a good idea. What does this buy you, besides the kind of abstract architectural benefits?

One thing you get is not having to call a bevy of constructors just to make a high-level object. Instead of new this and new that getting passed to new something else, the "rules" for creating the objects are laid out in a more declarative fashion.

Another thing is get is tighter control of object creation. For example, Guice lets you inject dependencies as singletons, so you only ever get one instance across all injections. As another example, a provider method gives you free rein to control exactly how objects are built.

Perhaps the most powerful thing you get is simple swapping of object creation systems. Suppose you want to perform some testing of the code that uses RouletteTable, and you need to be able to peek into and tweak the RouletteTable and RouletteWheel instances. No problem:
Injector injector = Guice.createInjector (new TestingModule());
Now you can create a module that generates objects designed for testing purposes. The code that uses those objects doesn't need to change at all.

That's quite enough about Guice. For more, check out its user's guide. Hopefully this quick tour of Guice has shown you how neat dependency injection is and what it can do for you.

Monday, March 7, 2011

What the heck is dependency injection?

In my travels through the Java world over the years, there have been some concepts which I've had trouble finding a simple, succinct definition for. One of them is "dependency injection" (DI), which is one of the hot Java concepts of the last few years. Let me try explaining what it is and why it's useful.

In the normal way of working with Java, you build your objects with constructors. A lot of the times, they need to build other objects they need.
class RouletteBall {}

class RouletteWheel {
  private RouletteBall ball;
  public RouletteWheel() {
    ball = new RouletteBall();
  }
}

class RouletteTable {
  private RouletteWheel wheel;
  private int numberOfSeats;
  public RouletteTable (int n) {
    numberOfSeats = n;
    wheel = new RouletteWheel();
  }
}
Very straightforward. When you ask for a new RouletteTable(), that constructor creates the necessary RouletteWheel, which in turn creates the necessary RouletteBall. The higher-level classes create their own dependencies.

There's another way to do this.

class RouletteBall {}

class RouletteWheel {
  private RouletteBall ball;
  public RouletteWheel (RouletteBall b) {
    ball = b;
  }
}

class RouletteTable {
  private RouletteWheel wheel;
  private int numberOfSeats;
  public RouletteTable (RouletteWheel w, int n) {
    numberOfSeats = n;
    wheel = w;
  }
}

// then you do this
RouletteWheel wheel = new RouletteWheel (new RouletteBall());
RouletteTable table = new RouletteTable (wheel, 8);
Oh snap, guess what, we just added dependency injection. But keep reading though, there's more to this.

The constructors here have been changed to take in the dependencies from outside, instead of generating them internally. The dependencies are supplied, or injected, into the class instances. Hence, dependency injection.

The term "inversion of control" (or IOC) is often applied to this sort of thing. The "control" refers to control over object creation, and the location of that control has been "inverted" from inside the classes to outside of them.

This doesn't seem particularly earth-shattering, and really it isn't at this point. Like a lot of design patterns, it's just a good idea, one that comes from the experience of many smart people working with object-oriented languages. It turns out that employing dependency injection gives you lots of flexibility.

For example, say we augmented our RouletteWheel class to be either European style (single-zero) or American style (double-zero).
class RouletteWheel {
  private RouletteBall ball;
  private boolean doubleZero;
  public RouletteWheel (RouletteBall b, boolean dz) {
    ball = b;
    doubleZero = dz;
  }
}
The first form of the RouletteTable class has a problem now, because its constructor needs to specify a style for the table's wheel. You'd have to add another parameter to the constructor, or maybe a second constructor. There are several ways to cope, but it involves some changes.

The second form of RouletteTable has no trouble with this change, because it just takes in whatever RouletteWheel instance it's handed. No code changes! This is also great because it encapsulates the details of how a RouletteWheel is created; the RouletteWheel class doesn't need to know or care about that.

I'm going to stop here for now. There's more to talk about, but I'd rather let the basic concept of dependency injection sink in. Next time I'll discuss how some frameworks support dependency injection and can help you out.