State-enforcement interfaces

Questo post lo scrivo in inglese, visto che è un’osservazione che parte da un post di Andrea, e il suo blog è in inglese.

Andrea raises the issue of objects whose state is not always valid for all their methods.
I’ll take a classic example where you must first invoke method 1 in order to be able to invoke method 2 :

connection.open(“url.of.server”);
connection.send(“foo”);

If you don’t open the connection first the send method will throw an exception.
This is obviously bad, as the user cannot simply presume that, since the object is available, he can use it. This requires extra-attention on the user side, and, unless the object’s creation is local, this extra-attention, even if applied, will translate into ifs, redundant method calls (calling open before every send, just to be sure) and so on.

The solution to this could be opening the connection at the moment of creation :

Connection connection = new Connection(“url.of.server”);
connection.send(“foo”);

This way, once you have the connection object in your hands, you know it will work.

Pity, though, that often it is not viable to open the connection at the moment of creating the object, for a thousand reasons, one for every flavor : optimization, security, release granularity (creating an object at every call forces us to deal with concrete classes or factories) and many more.

This is true for all sorts of objects which are intrinsically multi-state and whose states cannot satisfy all methods.

Careful here, most cases of objects which happen to be partially initialized are just the result of faulty design, not to forget the excellent practice of savage javabeaning and zero-argument constructors.

So, when all else fails, I’ve found that I may prevent most mishaps on the user side by implementing a nice idiom I first saw in jMock.

In this idiom I basically reckon that, since not all methods are supported in a given state of the object, the object should be used only through an interface that offers just those methods that are supported by the current state.

In the previous example I would define the Connection class this way :

public class Connection implements NewConnection, OpenConnection {

    public static NewConnection create(String url) {
        return new Connection(url);
    }

    private final String url;

    private Connection(String url) {
        this.url = url;
    }

    public OpenConnection open() {
        //Do stuff with the url and open the connection
        return this;
    }

    public void send(String message) {
        //Send the message
    }

}

The two interfaces look like this :

public interface NewConnection {

    OpenConnection open();

}

public interface OpenConnection {

    void send(String message);

}

Why the factory? Because I want to enforce the fact that when I create a new connection it is a “NewConnection”, a use sample :

NewConnection newConnection = Connection.creaet(“url.of.server”);
newConnection.open().send(message);

Having learned this idiom by looking at jMock, I have yet to find the paper where this idiom/pattern is defined and thus I’ve invented a name for it : “state-enforcement interfaces”, as it allows the developer of a component to guide the user along valid sequences of method calls.

An object may implement a lot of interfaces, with each interface defining one or more methods that transition the object to a different interface. If we make sure that all methods return the object itself this idiom is a very readable yet compact way of performing complex conditional initializations, if we then forget about the classic “verb = method, noun = object” rule we can make it really look like a language :

NewConnection newConnection = CreateA.http().connection().to(“url.of.server”).onPort(80);
ListeningServer server = CreateA.ftp().server().listeningOnPort(6945).allowing(60).users().every(30).minutes();

The best thing is that this little language has its syntax enforced by the various interfaces and their transitions.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s