CumulativeFactory

From APIDesign

(Difference between revisions)
Jump to: navigation, search
Current revision (12:30, 15 November 2008) (edit) (undo)
m (APIDesignPatterns:CumulativeFactory moved to CumulativeFactory: Shorter names for use with categories)
 
(One intermediate revision not shown.)
Line 13: Line 13:
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:
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:
-
<source lang="java" snippet="aserverinfo.cumulative.creation"/>
+
<source lang="java" snippet="ServerConnector.cumulative.creation"/>
-
This pattern keeps the [[Declarative Programming]] benefits, while eliminating many overloaded factory methods.
+
This pattern keeps the [[Declarative Programming]] benefits, while eliminating many overloaded factory methods. Similar patterns include [[APIDesignPatterns:Builder]] or plain [[APIDesignPatterns:Factory]]
<comments/>
<comments/>
 +
 +
[[Category:APIDesignPatterns]]
 +
[[Category:APIDesignPatterns:Creational]]

Current revision

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