Clean up your kids toy box with the loan pattern

June 03, 2014

Take a look at the following piece of code:

public class ToyBox {

    public ToyBox() {
    }

    public ToyBox open() {
        System.out.println("Open toy box :)");
        return this;
    }

    public ToyBox lego() {
        System.out.println("Play with lego!");
        return this;
    }

    public ToyBox meccano() {
        System.out.println("Play with meccano!");
        return this;
    }

    public ToyBox cleanUpToys() {
        System.out.println("Clean up toys :(");
        return this;
    }

    public void close() {
        System.out.println("Close toy box");
    }
}
     new ToyBox().open()
                .lego()
                .meccano()
                .cleanUpToys()
                .close(); 
Open toy box :)  
Play with lego!  
Play with meccano!  
Clean up toys :(  
Close toy box  

What we see is an example of the classic builder pattern. By using method chaining, your kid can keep playing with his toys. Afterwards, he can clean up his toys and close the box.
At first sight this seems a fairly good approach but what happens in reality?
Your kid opens the box, plays with all the toys until the box is empty, and leaves all the toys scattered around the room!

The builder pattern exposes a lot of functionality, and by doing, it gives a lot of responsibility to the code/programmer. Often, we need to enforce certain steps, in a correct order, to ensure that our algorithm is behaving the way we designed it. In this particular case, we first need to open the box, play with the toys, and afterwards clean up and close the box.

How can we enforce this logic?
The toy box should be responsible for the obligatory steps.
First, lets open the box when creating an instance, and make the constructor private.

    private ToyBox() {
        open();
    } 

Secondly, introduce a static method play, which creates an instance of a toy box.
This method will be used to interact with our toy box.

    public static void play() {
        final ToyBox box = new ToyBox();
    }

We have to clean up all toys and close the box, before we lose the reference to our instance and wait for the garbage collector to dispose the object.

     public static void play() {
        final ToyBox box = new ToyBox();

        box.cleanUpToys()
                .close();
    } 
        ToyBox.play();
Open toy box :)  
Clean up toys :(  
Close toy box  

You'll notice that we have created a useless box. However we have enforced that all toys are cleaned up before closing the box.

But how do we play with the toys?
Lets add a parameter to the play method: java.lang.function.Consumer block.
This parameter is a consumer of ToyBox, which means it expects a method returning ToyBox. Or even nicer, a method chain!

We can execute this consumer by invoking the accept method, and pass the toy box instance as a reference.

   public static void play(final Consumer<ToyBox> block) {
        final ToyBox box = new ToyBox();

        block.accept(box);

        box.cleanUpToys()
                .close();
    } 

Now we can play around inside the play method!

        ToyBox.play(box -> box.lego().meccano());

As last step, we make the open/close/tidy up methods private and of we go!

import java.util.function.Consumer;

public class ToyBox {

    private ToyBox() {
        open();
    }

    public static void play(final Consumer<ToyBox> block) {
        final ToyBox box = new ToyBox();

        block.accept(box);

        box.cleanUpToys()
                .close();
    }

    private ToyBox open() {
        System.out.println("Open toy box :)");
        return this;
    }

    public ToyBox lego() {
        System.out.println("Play with lego!");
        return this;
    }

    public ToyBox meccano() {
        System.out.println("Play with meccano!");
        return this;
    }

    private ToyBox cleanUpToys() {
        System.out.println("Clean up toys :(");
        return this;
    }

    private void close() {
        System.out.println("Close toy box");
    }
}
        ToyBox.play(box -> box.lego().meccano());
Open toy box :)  
Play with lego!  
Play with meccano!  
Clean up toys :(  
Close toy box  

Code is available on github

Conclusion

The loan pattern is particularly useful for dealing with resources. Using this approach, you can create a fluent api and still be sure that your algorithm is behaving the way you intended it.

References

Functional Programming in Java: Harnessing the Power Of Java 8 Lambda Expressions By Venkat Subramaniam

Jeroen Bellen
Alken
Dissident blogger!