Definition
The step builder pattern is an extension of the builder pattern that fully guides the user through the creation of the object with no chances of confusion. [1]
Contents |
The intent of the Step Builder design pattern is to separate the construction of a complex object from its representation by creating defined steps and exposing to the user only selected methods per time.
Advantages of using the Step Builder over the Builder pattern
- The user will see only one or few selected methods per time during the Object creation.
- Based on the user choice different paths can be taken during the Object creation.
- The final build step will be available only at the end, after all mandatory steps are completed, returning an Object in a consistent state.
- The user experience will be greatly improved by the fact that he will only see the next step methods available.
Examples
Java
/** "Product" */
class UserConfiguration {
private final String name;
private final String filePath;
private ServerDetails serverDetails;
public UserConfiguration(String name, String filePath){
this.name = name;
this.filePath = filePath;
}
public void setServerDetails(ServerDetails serverDetails) { this.serverDetails = serverDetails; }
//all the getters
...
}
class ServerDetails {
private final String host;
private String user;
private String password;
public ServerDetails(String host){
this.host = host;
}
public void setUser(String user) { this.user = user; }
public void setPassword(String password) { this.password = password; }
//all the getters and isLocalhost() method
...
}
/** "Step Builder" */
public class UserConfigurationBuilder {
public static NameStep newBuilder() {
return new Steps();
}
private UserConfigurationBuilder() {}
public static interface NameStep {
/**
* @param name unique identifier for this User Configuration
* @return FileStep
*/
FileStep name(String name);
}
public static interface FileStep {
/**
* @param filePath absolute path of where the User Configuration exists.
* @return ServerStep
*/
ServerStep filePath(String name);
}
public static interface ServerStep {
/**
* The hostname of the server where the User Configuration file is stored will be set to "localhost".
* @return BuildStep
*/
public BuildStep onLocalhost();
/**
* The hostname of the server where the User Configuration file is stored.
* @return CredentialsStep
*/
public CredentialsStep onRemotehost(String host);
}
public static interface CredentialsStep {
/**
* Username required to connect to remote machine
* Password required to connect to remote machine
* @return BuildStep
*/
public BuildStep credentials(String user, String password);
}
public static interface BuildStep {
/**
* @return an instance of a UserConfiguration based on the parameters passed during the creation.
*/
public Profile build();
}
private static class Steps implements NameStep, FileStep, ServerStep, CredentialsStep, BuildStep {
private String name;
private String host;
private String user;
private String password;
private String filePath;
@Override
public FileStep name(String name) {
this.name = name;
return this;
}
@Override
public ServerStep filePath(String filePath) {
this.filePath = filePath;
return this;
}
@Override
public BuildStep onLocalhost() {
this.host = "localhost";
return this;
}
@Override
public CredentialsStep onRemotehost(String host) {
this.host = host;
return this;
}
@Override
public BuildStep credentials(String user, String password) {
this.user = user;
this.password = password;
return this;
}
@Override
public UserConfiguration build() {
UserConfiguration userConfiguration = new UserConfiguration(name, filePath);
ServerDetails serverDetails = new ServerDetails(host);
if (!serverDetails.isLocalhost()) {
serverDetails.setUser(user);
serverDetails.setPassword(password);
}
userConfiguration.setServerDetails(serverDetails);
return userConfiguration;
}
}
}
/** A user creating a configuration. */
class StepBuilderExample {
public static void main(String[] args) {
// A local user configuration
UserConfiguration localUserConfiguration = UserConfigurationBuilder
.newBuilder()
.name("aLocalConfiguration")
.filePath("/opt/conf/user.txt")
.onLocalhost()
.build();
// A remote user configuration
UserConfiguration remoteUserConfiguration = UserConfigurationBuilder
.newBuilder()
.name("aRemoteConfiguration")
.filePath("/opt/conf/user.txt")
.onRemotehost("172.x.x.x")
.credentials("user","password")
.build();
}
}
Java
/** "Product" */ class UserConfiguration { private final String name; private final String filePath; private ServerDetails serverDetails; public UserConfiguration(String name, String filePath){ this.name = name; this.filePath = filePath; } public void setServerDetails(ServerDetails serverDetails) { this.serverDetails = serverDetails; } //all the getters ... } class ServerDetails { private final String host; private String user; private String password; public ServerDetails(String host){ this.host = host; } public void setUser(String user) { this.user = user; } public void setPassword(String password) { this.password = password; } //all the getters and isLocalhost() method ... } /** "Step Builder" */ public class UserConfigurationBuilder { public static NameStep newBuilder() { return new Steps(); } private UserConfigurationBuilder() {} public static interface NameStep { /** * @param name unique identifier for this User Configuration * @return FileStep */ FileStep name(String name); } public static interface FileStep { /** * @param filePath absolute path of where the User Configuration exists. * @return ServerStep */ ServerStep filePath(String name); } public static interface ServerStep { /** * The hostname of the server where the User Configuration file is stored will be set to "localhost". * @return BuildStep */ public BuildStep onLocalhost(); /** * The hostname of the server where the User Configuration file is stored. * @return CredentialsStep */ public CredentialsStep onRemotehost(String host); } public static interface CredentialsStep { /** * Username required to connect to remote machine * Password required to connect to remote machine * @return BuildStep */ public BuildStep credentials(String user, String password); } public static interface BuildStep { /** * @return an instance of a UserConfiguration based on the parameters passed during the creation. */ public Profile build(); } private static class Steps implements NameStep, FileStep, ServerStep, CredentialsStep, BuildStep { private String name; private String host; private String user; private String password; private String filePath; @Override public FileStep name(String name) { this.name = name; return this; } @Override public ServerStep filePath(String filePath) { this.filePath = filePath; return this; } @Override public BuildStep onLocalhost() { this.host = "localhost"; return this; } @Override public CredentialsStep onRemotehost(String host) { this.host = host; return this; } @Override public BuildStep credentials(String user, String password) { this.user = user; this.password = password; return this; } @Override public UserConfiguration build() { UserConfiguration userConfiguration = new UserConfiguration(name, filePath); ServerDetails serverDetails = new ServerDetails(host); if (!serverDetails.isLocalhost()) { serverDetails.setUser(user); serverDetails.setPassword(password); } userConfiguration.setServerDetails(serverDetails); return userConfiguration; } } } /** A user creating a configuration. */ class StepBuilderExample { public static void main(String[] args) { // A local user configuration UserConfiguration localUserConfiguration = UserConfigurationBuilder
.newBuilder() .name("aLocalConfiguration") .filePath("/opt/conf/user.txt") .onLocalhost() .build(); // A remote user configuration UserConfiguration remoteUserConfiguration = UserConfigurationBuilder
.newBuilder() .name("aRemoteConfiguration") .filePath("/opt/conf/user.txt") .onRemotehost("172.x.x.x") .credentials("user","password") .build(); } }
C#
namespace StepBuilder
{
class Program
{
static void Main(string[] args)
{
UserConfiguration localUserConfiguration = UserConfigurationBuilder .CreateNewBuilder() .SetName(@"aLocalConfiguration") .SetFilePath(@"/opt/conf/user.txt") .OnLocalhost() .Build();UserConfiguration remoteUserConfiguration = UserConfigurationBuilder .CreateNewBuilder() .SetName(@"aRemoteConfiguration") .SetFilePath(@"/opt/conf/user.txt") .OnRemoteHost("172.x.x.x") .SetCredentials("user", "password") .Build(); } } public class UserConfiguration { public UserConfiguration(string name, string filePath) { Name = name; FilePath = filePath; } private ServerDetails _serverDetails; public string Name { get; private set; } public string FilePath { get; private set; } public void SetServerDetails(ServerDetails serverDetails) { _serverDetails = serverDetails; } } public class ServerDetails { public ServerDetails(string host) { Host = host; } public string Host { get; private set; } public string User { get; set; } public string Password { get; set; } public bool IsLocalhost { get { return Host == "localhost"; } } } public class UserConfigurationBuilder { public static INameStep CreateNewBuilder() { return new Steps(); } private UserConfigurationBuilder() { } public interface INameStep { /// <param name="name">Unique identifier for this User Configuration</param> IFileStep SetName(string name); } public interface IFileStep { /// <param name="filePath">Absolute path of where the User Configuration exists</param> IServerStep SetFilePath(string filePath); } public interface IServerStep { /// <summary> /// The hostname of the server where the User Configuration file is store will be set to "localhost". /// </summary> IBuildStep OnLocalhost(); /// <param name="host">The hostname of the server where the User Configuration is stored</param> ICredentialsStep OnRemoteHost(string host); } public interface IBuildStep { /// <summary> /// Returns an instance of a UserConfiguration based on the parameters passed during the creation. /// </summary> UserConfiguration Build(); } public interface ICredentialsStep { /// <param name="user">Username required to connect to remote machine</param> /// /// <param name="password">Password required to connect to remote machine</param> IBuildStep SetCredentials(string user, string password); } private class Steps : INameStep, IFileStep, IServerStep, IBuildStep, ICredentialsStep { private string _name; private string _host; private string _user; private string _password; private string _filePath; public IFileStep SetName(string name) { _name = name; return this; } public IServerStep SetFilePath(string filePath) { _filePath = filePath; return this; } public IBuildStep OnLocalhost() { _host = "localhost"; return this; } public ICredentialsStep OnRemoteHost(string host) { _host = host; return this; } public UserConfiguration Build() { UserConfiguration userConfiguration = new UserConfiguration(_name, _filePath); ServerDetails serverDetails = new ServerDetails(_host); if (!serverDetails.IsLocalhost) { serverDetails.Password = _password; serverDetails.User = _user; } userConfiguration.SetServerDetails(serverDetails); return userConfiguration; } public IBuildStep SetCredentials(string user, string password) { _user = user; _password = password; return this; } } } }