Monday 8 October 2012

Step Builder Pattern - WIKI-Definition


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

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