CumulativeFactory

From APIDesign

Jump to: navigation, search

Cumulative Factory is pattern that allows the API Designers get benefits of getters and setters while exploring the benefits of Declarative Programming. Imagine that you have an API with getters and few callable methods:

Code from ServerConnector.java:
See the whole file.

/** A class to connect to server, identify it and manipulate with
 * its state. The <a href="http://apidesign.org">Practical API Design</a>
 * book used to call it AServerInfo.
 * <p>
 */
public final class ServerConnector {
    public String getName() {
        return name == null ? "noname" : name.getName();
    }
 
    public URL getURL() {
        return url == null ? null : url.getURL();
    }
 
    public void reset() {
        if (reset != null) {
            reset.reset();
        }
    }
 
    /** Additional method for API clients not available from first version.
     * @since 2.0
     */
    public void shutdown() {
        if (shutdown != null) {
            shutdown.shutdown();
        }
    }
}
 

Now you may want to let the API users modify these fields. One option is to provide setters for each getter. However that immediately turns instances of the AServerInfo class into mutable objects. As lifecycle of mutable objects is more complicated and as the simpler API semantics the better, it may make sense to search for alternatives. One of them is regular factory with a single factory method:

Code from ServerConnector.java:
See the whole file.

public static ServerConnector create(
    NameProvider nameProvider, 
    URLProvider urlProvider, 
    ResetHandler reset
)
 

This is indeed acceptable solution, yet it suffers from enormous duplication of factory methods. As the API is evolving, it adds more and more getters and each such addition requires new overloaded version of the factory method. This proliferation of many methods with same name and different arguments may not be fully desirable. In such case, one can benefit from using Cumulative Factory:

Code from ServerConnector.java:
See the whole file.

public static ServerConnector empty() {
    return new ServerConnector(null, null, null, null);
}
 
public final ServerConnector nameProvider(NameProvider np) {
    return new ServerConnector(np, this.url, this.reset, this.shutdown);
}
 
public final ServerConnector urlProvider(URLProvider up) {
    return new ServerConnector(this.name, up, this.reset, this.shutdown);
}
public final ServerConnector reset(ResetHandler h) {
    return new ServerConnector(this.name, this.url, h, this.shutdown);
}
/** All one needs to do when there is a need to add new
 * style of creation is to add new <em>clonning</em> method.
 * @param handler
 * @return
 * @since 2.0
 */
public final ServerConnector shutdown(ShutdownHandler handler) {
    return new ServerConnector(this.name, this.url, this.reset, handler);
}
 

This pattern is based on one real factory method that creates base version of the object and many instance cloning methods that take the values in provided prototype instance, copy them and modify just one attribute, returning new clone. The usage can then chain the cloning to obtain instances with all desired attributes:

Code from CummulativeFactoryTest.java:
See the whole file.

inf = ServerConnector.empty().nameProvider(np).urlProvider(up).reset(res);
 

This pattern keeps the Declarative Programming benefits, while eliminating many overloaded factory methods. Similar patterns include APIDesignPatterns:Builder or plain APIDesignPatterns:Factory

<comments/>

Personal tools
buy