Agile Zone is brought to you in partnership with:

As an Agile Coach, Miško is responsible for teaching his co-workers to maintain the highest level of automated testing culture, allowing frequent releases of applications with high quality. He is very involved in Open Source community and an author of several open source projects. Recently his interest in Test Driven Developement turned into http://TestabilityExplorer.org with which he hopes will change the testing culture of the open source community. Misko is a DZone MVB and is not an employee of DZone and has posted 38 posts at DZone. You can read more from them at their website. View Full User Profile

Application Wiring on Auto-Pilot

09.24.2008
| 6009 views |
  • submit to reddit

We talked about how it is important to separate the new operators from the application logic. This separation forces your code to have factories which are responsible for wiring your application together. By separating this responsibility the tests can always wire together a subset of an application with key components replaced for friendlies making testing easier and more focused.

But lets look at a sample factory

class CarFactory {
Car create() {
return new Car(
new EngineCompartment(
new Engine(),
new ManualTransmission(),
new PowerSteering(),
new Battery()
),
new Cabin(
new Door(new PowerWindow()),
new Door(new PowerWindow()),
new PowerSeat(), new PowerSeat()
),
Arrays.asList(
new Wheel(new Tire(), new Rim()),
new Wheel(new Tire(), new Rim()),
new Wheel(new Tire(), new Rim()),
new Wheel(new Tire(), new Rim())
)
);
}
}

This factory builds a car. The first thing to notice is that all of the new-operators are here (If you were to look inside each of the classes it would be devoid of “new”s). The second, is a complete lack of logic (no loops or conditions). And finally the third, your application behavior is controlled by the way the classes are wired together. If I wanted a automatic-transmission car, all we have to do is to wire the classes differently. The wiring responsibility is in the factory class not with the application logic.

However, why do we need to tell the JVM how to wire these Classes together? Is it not self obvious? After all look at the constructors of these classes:

Car(EngineCompartment ec, Cabin c, List<Wheel> ws);
EngineCompartment(Engine e, Transmission t,
Steering s, Battery b);
Cabin(Door driverDoor, Door pasangerDoor,
Seat driverSear, Seat passangerSear);
Engine(float dissplacement, int pistonCount);
Battery(float voltage);
Door(Window window);
PowerWindow() implements Window;
PowerSeat() implements Seat;
Wheel(Tire tire, Rim rim);
...

Imagine you could just ask for things. Lets start simple and look at the Wheel. The constructor of Wheel needs a Tire and Rim. So when we ask for a Wheel it should be self obvious that we want new Wheel(new Tire(), new Rim()). Why do we need to make this explicit in our factory? Lets build a framework from which we can ask for a class and it returns an instance of that class. So in our case if we ask for getInstance(Wheel.class) it returns instance of new Wheel(new Tire(), new Rim()). Now a framework like this is easy to build since all we need to do is look at the constructor and recursively try to instantiate the objects until all recursive constructors are satisfied.

But things are a bit more complicated than that. What if we ask for Cabing as in getInstance(Cabin.class). Well Cabin needs two Doors and two Seats, but Seat is an interface and so we have to make a decision. What subclass of Seat should we instantiate. To help our framework make that decision we will add a bind method such as bind(Seat.class, PowerSeat.class). Great now we call get(Seat.class) the framework returns new PowerSeat(). Similarly, we will have to call bind(Window.class, PowerWindow.class). Now we can call get(Cabin.class) and the framework will return new Cabin(new Door(new PowerWindow()), new Door(new PowerWindow()), new PowerSeat(), new PowerSeat()).

Notice that a closer to the root a class, the class you ask for is, the more work will the framework do for us. So ideally we just want to ask for the root object. In our case Car. Calling get(Car.class) will cause the framework to do all of the work originally in our factory.

As you can see a framework which will call the new operators on your behalf is very useful. This is because you only have to ask for the root object (in our case the Car) and the framework will build the whole object graph on your behalf. This kinds of frameworks are called Automatic Dependency Injection frameworks and there are few of them our there. Namely GUICE, PicoContainer, and Spring.

Since I know most about GUICE, The above example can be rewritten in GUICE like this:

class CarModule extends AbstractModule() {
public void bind() {
bind(Seat.class, PowerSeat.class);
bind(Seat.class, PowerSeat.class);
bind(Transmission.class, ManualTransmission.class);
bind(new TypeLitteral<List<Wheel>>(){})
.toProvider(new Provider<List<Wheel>>(){
@Inject Provider<Wheel> wp;
List<Wheel> get() {
return Array.asList(wp.get(), wp.get(),
wp.get(), wp.get());
}
});
}
}
Injector injector;
injector = GUICE.createInjector(new CarModule());
Car car = injector.getInstance(Car.class);

As you can see Automatic Dependency Injection frameworks can do a lot of things for you. Namely, that you don’t have to worry about writing the factories. You simply write your application logic and ask for your dependencies in the constructor and let the framework resolve all of them for you. You move the responsibility of calling the new operator to the framework. Or to put it differently DI-framework is your new “new”. Now DI-frameworks can do lot of other things, which are beyond the scope of this article, such as manage object lifetimes, enforce singletons (in a good way, see: Root Cause of Singletons and Singletons are Pathological Liars) and manage different configurations of your application such as production vs development server.

For a more real life example of a GUICE Module see: CalculatorServerModule.java

Originally posted on Miško Hevery - The Testability Explorer Blog

Published at DZone with permission of Misko Hevery, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)