Builder

From APIDesign

(Difference between revisions)
Jump to: navigation, search
Line 1: Line 1:
[[APIDesignPatterns:Builder|Builder pattern]] is composed from inital configuration [[APIDesignPatterns:CumulativeFactory|cumulative factory]] pattern phase followed by final call to a [[APIDesignPatterns:Factory|factory method]]. It is very useful, especially in cases where the intermediate states created by the use of [[APIDesignPatterns:CumulativeFactory|cumulative factory]] are incomplete and cannot be used by itself. If an additional action (write to disk, establish connnection, etc.) is needed, it makes sense to finish the API calls by final use of [[APIDesignPatterns:Factory|factory method]].
[[APIDesignPatterns:Builder|Builder pattern]] is composed from inital configuration [[APIDesignPatterns:CumulativeFactory|cumulative factory]] pattern phase followed by final call to a [[APIDesignPatterns:Factory|factory method]]. It is very useful, especially in cases where the intermediate states created by the use of [[APIDesignPatterns:CumulativeFactory|cumulative factory]] are incomplete and cannot be used by itself. If an additional action (write to disk, establish connnection, etc.) is needed, it makes sense to finish the API calls by final use of [[APIDesignPatterns:Factory|factory method]].
-
Imagine that we have an API representing a server:
+
Imagine that we have an API representing a server...
<source lang="java" snippet="aserverinfo.builder.api"/>
<source lang="java" snippet="aserverinfo.builder.api"/>
-
And we need a way to establish connection to it. For that purpose we can define additional class that has no ''getters'', no way to obtain its state via external APIs. Instead it offers users of its API only ''setters'' (or in this case cumulative factory methods) allowing the clients to change enough properties before final creation of the connector:
+
...and we need a way to establish connection to it. For that purpose we can define additional class that has no ''getters'', no way to obtain its state by external API clients. Instead it offers users of its API only ''setters'' (or in this case cumulative factory methods) allowing the clients to change enough properties before final creation of the connector is done:
<source lang="java" snippet="aserverinfo.builder.factory"/>
<source lang="java" snippet="aserverinfo.builder.factory"/>
-
The use is similar as in case of [[APIDesignPatterns:CumulativeFactory|cumulative factory]], just the writer of the API can simplify internals of the '''ServerInfo''' class, as it is know to never connect directly, to the server, it is just a recipe for creation of the connection:
+
The API use is not complicated over the case of [[APIDesignPatterns:CumulativeFactory|cumulative factory]]. Moreover the writer of the API can simplify internals of his '''ServerInfo''' class, as the class is know to never connect directly to any server. The class is just a recipe for creation of the connection:
<source lang="java" snippet="ServerConnector.builder.creation.verbose"/>
<source lang="java" snippet="ServerConnector.builder.creation.verbose"/>
-
The previous snippet is the verbose way to use the API, the shorter one liner looks like:
+
The previous code snippet shows the verbose way to use the API. The shorter one-liner is also possible:
<source lang="java" snippet="ServerConnector.builder.creation"/>
<source lang="java" snippet="ServerConnector.builder.creation"/>
-
[[APIDesignPatterns:Builder|Builder pattern]] evolution characteristics are simpler to [[APIDesignPatterns:CumulativeFactory|cumulative factory]] pattern, yet in some situations can its use simplify internal implementation of the [[API]].
+
[[APIDesignPatterns:Builder|Builder pattern]] evolution characteristics are similar to the ones of the [[APIDesignPatterns:CumulativeFactory|cumulative factory]] pattern. Yet the clear separation between configuration and functional part of the [[API]] may, in some situations, simplify internal implementation and prevent misuses (calling a ''setter'' after making the connection) of the class.
<comments/>
<comments/>

Revision as of 13:10, 15 November 2008

Builder pattern is composed from inital configuration cumulative factory pattern phase followed by final call to a factory method. It is very useful, especially in cases where the intermediate states created by the use of cumulative factory are incomplete and cannot be used by itself. If an additional action (write to disk, establish connnection, etc.) is needed, it makes sense to finish the API calls by final use of factory method.

Imagine that we have an API representing a server...

Code from ServerConnector.java:
See the whole file.

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();
        }
    }
}
 

...and we need a way to establish connection to it. For that purpose we can define additional class that has no getters, no way to obtain its state by external API clients. Instead it offers users of its API only setters (or in this case cumulative factory methods) allowing the clients to change enough properties before final creation of the connector is done:

Code from ServerInfo.java:
See the whole file.

public class ServerInfo {
 
    public static ServerInfo empty() {
        return new ServerInfo(null, null, null, null);
    }
 
    public final ServerInfo nameProvider(NameProvider np) {
        this.name = np;
        return this;
    }
 
    public final ServerInfo urlProvider(URLProvider up) {
        this.url = up;
        return this;
    }
    public final ServerInfo reset(ResetHandler h) {
        this.reset = h;
        return this;
    }
 
    /** All one needs to do when there is a need to add new
     * style of creation is to add new method for a builder.
     * @param handler
     * @return
     * @since 2.0
     */
    public final ServerInfo shutdown(ShutdownHandler handler) {
        this.shutdown = handler;
        return this;
    }
 
    /** Creates the server connector based on current values in the 
     * info. Builder factory method.
     * @return server connector
     */
    public final ServerConnector connect() {
        return new ServerConnector(name, url, reset, shutdown);
    }
}
 

The API use is not complicated over the case of cumulative factory. Moreover the writer of the API can simplify internals of his ServerInfo class, as the class is know to never connect directly to any server. The class is just a recipe for creation of the connection:

Code from BuilderFactoryTest.java:
See the whole file.

ServerInfo empty = ServerInfo.empty();
ServerInfo name = empty.nameProvider(prov);
ServerInfo urlAndName = name.urlProvider(prov);
ServerInfo all = urlAndName.reset(prov);
connection = all.connect();
 

The previous code snippet shows the verbose way to use the API. The shorter one-liner is also possible:

Code from BuilderFactoryTest.java:
See the whole file.

connection = ServerInfo.empty()
        .nameProvider(np).urlProvider(up).reset(res).connect();
 

Builder pattern evolution characteristics are similar to the ones of the cumulative factory pattern. Yet the clear separation between configuration and functional part of the API may, in some situations, simplify internal implementation and prevent misuses (calling a setter after making the connection) of the class.

<comments/>

Personal tools
buy