打造智能建筑商
构建API时,您应该始终考虑谁将使用它。 当API简单易用时,用户就会感到满意。 当用户满意时,每个人也都会满意。 但是出色的可用性并非总是容易实现的。 有一些模式对此有所帮助,在这篇文章中,我将重点介绍经典的构建器模式,以及如何使用步进构建器模式对其进行增强,以构建没有大脑接口,易于使用且不会出错的对象 。 因此,让我们开始绘制一些上下文,我们有2个域对象代表连接到某个远程或本地服务器的用户配置。 当需要远程凭据时,在本地时。
package com.marco.sbp; public class UserConfiguration { private final String name; private ServerDetails serverDetails; public UserConfiguration(String name) { this.name = name; } public void setServerDetails(ServerDetails serverDetails) { this.serverDetails = serverDetails; } public String getName() { return name; } public ServerDetails getServerDetails() { return serverDetails; } }
package com.marco.sbp; public 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; } public String getHost() { return host; } public String getUser() { return user; } public String getPassword() { return password; } }
我们希望使用两种不同的技术(经典的构建器模式和步骤构建器模式)来抽象上述对象的构造。
经典的构建器模式非常简单,它使用诸如onLocalHost,onRemoteHost等正确命名的方法来掩盖UserConfiguration和ServerDetails的创建。
package com.marco.sbp.builder; import com.marco.sbp.ServerDetails; import com.marco.sbp.UserConfiguration; public class ClassicBuilder { private String name; private String host; private String user; private String password; public ClassicBuilder(String name){ this.name = name; } public ClassicBuilder onLocalHost(){ this.host = "localhost"; return this; } public ClassicBuilder onRemoteHost(String remoteHost){ this.host = remoteHost; return this; } public ClassicBuilder credentials(String user, String password){ this.user = user; this.password = password; return this; } public UserConfiguration build(){ UserConfiguration userConfiguration = new UserConfiguration(name); ServerDetails serverDetails = new ServerDetails(host); serverDetails.setUser(user); serverDetails.setPassword(password); userConfiguration.setServerDetails(serverDetails); return userConfiguration; } }
步骤构建器模式仍在使用智能名称来构造对象,但是仅在需要使用接口和适当的封装时才公开这些方法。
package com.marco.sbp.builder; import com.marco.sbp.ServerDetails; import com.marco.sbp.UserConfiguration; /** "Step Builder" */ public class StepBuilder { public static NameStep newBuilder() { return new Steps(); } private StepBuilder() { } public static interface NameStep { /** * @param name * unique identifier for this User Configuration * @return ServerStep */ ServerStep name(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 UserConfiguration build(); } private static class Steps implements NameStep, ServerStep, CredentialsStep, BuildStep { private String name; private String host; private String user; private String password; public BuildStep onLocalhost() { this.host = "localhost"; return this; } public ServerStep name(String name) { this.name = name; return null; } public CredentialsStep onRemotehost(String host) { this.host = host; return this; } public BuildStep credentials(String user, String password) { this.user = user; this.password = password; return this; } public UserConfiguration build() { UserConfiguration userConfiguration = new UserConfiguration(name); ServerDetails serverDetails = new ServerDetails(host); serverDetails.setUser(user); serverDetails.setPassword(password); userConfiguration.setServerDetails(serverDetails); return userConfiguration; } } }
现在让我们看一下两个构建器的用户体验。 经典构建器将使用用户配置的名称来构造,然后它将公开其所有方法,从而使用户过于自由,无法选择下一步。
例如,一个不小心的用户可能最终将UserConfiguration设置为localhost,而无需身份验证,仍然传递用户名和密码。
这令人困惑,并且可能导致运行时异常。
这些是用户可以最终得到的UserConfigurations的一些可能组合,其中一些是正确的,很多是错误的:
步骤构建器有一个完全不同的故事,这里仅显示了当时的一个步骤:
如果不需要凭据,则不会公开它们,只有在确保对象状态一致且完整时才提供build()方法:
使用此模式只能构建2个可能的UserConfigurations,它们既有意义又对用户清楚。
结论
步骤构建器模式不是经典Bloch 模式的替代,有时您想强迫用户在进行创建之前填充一些参数,在这种情况下,步骤构建器正在执行此工作,否则,当需要更开放的方法时比经典的建造者更适合您。
翻译自: https://www.javacodegeeks.com/2013/05/building-smart-builders.html