调整Builder模式以进行方法调用

这是尝试从Effective Java 2nd Edition中仔细理解ITEM 40:设计方法签名的一部分。

建议改进方法签名可读性的一个目的是瞄准四个或更少的参数。 建议使用多种技术管理较长的参数列表,其中一种技术如下:

结合前两个方面的第三种技术是使Builder模式(第2项)从对象构造适应方法调用。 如果你有一个包含许多参数的方法,特别是如果它们中的一些是可选的,那么定义一个代表所有参数的对象并允许客户端对这个对象进行多次“setter”调用是有益的。它设置单个参数或小的相关组。 一旦设置了所需的参数,客户端就会调用对象的“执行”方法,该方法对参数进行任何最终有效性检查并执行实际计算。

我熟悉Builder模式,因为它用于构造对象,但我不确定我是否正确理解了如何使其适应方法调用。

这是我到目前为止:
(我试图改进move方法的方法调用)

 public class Space { public static class Builder { // Required parameters private final int x; private final int y; private final int z; // optional params private long time = 0; public Builder(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } public Builder time(long val) { time = val; return this; } public void move() { if (x == 0 || y == 0 || z == 0) { throw new IllegalArgumentException("Cannot move to the centre of the universe"); } // Do the actual work here } } // public void move(int x, int y, int z, long time) { // // Do the work here // } public static void main(String[] args) { new Builder(1, 1, -1).time(1234).move(); } } 

我对Joshua Bloch的建议的解释是否正确?

我已经使用在我要实例化的类中定义的接口完成了Builder模式的修改。

有关此内容和相关“双向构建器”的更多信息,请参见此处: http : //www.javaworld.com/javaworld/jw-01-2004/jw-0102-toolbox.html? page = 3

我会做类似以下的事情; 虽然这对于3个必填字段来说可能有点过分,但是在考虑每个必需字段的同时构建更大的对象非常有用。

 public Class Space { public interface Builder { public Space build(); public int x(); public int y(); public int z(); } // Build a complete Space object accounting for every field. public Space(Space.Builder spaceBuilder) { this.x = spaceBuilder.x(); this.y = spaceBuilder.y(); this.z = spaceBuilder.z(); this.time = builder.time(); } // Might not be necessar if you update time when you update x, y, and z public Builder time(long val) { time = val; return this; } public void move() { // ... } public static void main(String[] args) { new Builder() { @Override public Space build(){ return new Space(this);} @Override public int x(){ return 1;} @Override public int y{ return 1;} @Override int z{ return -1;} }.build().time(1234).move(); } } 

我看到它的方式,你的构建器类与父类相关联(就像使用非静态内部类 ),客户端会像这样使用它:

 Space space = new Space(); ... Space.MoveBuilder moveBuilder = space.new MoveBuilder(1, 1, -1); moveBuilder.setTime(1234); moveBuilder.execute(); 

可以通过使用流畅的构建器和工厂方法进一步简化:

 space.startMove(1, 1, -1).withTime(1234).endMove(); 

我创建了Java Method Invocation Builder ,它在编译时生成调用方法的构建器。 它还增加了对Java中方法参数的默认值的支持。

它可以在类或接口上使用。 通过将@GenerateMethodInvocationBuilder@Default注释添加到类型中。

 @GenerateMethodInvocationBuilder public interface BitBucketServerService { @GET("/rest/api/1.0/projects/{projectkey}/repos/{repositoryslug}/pull-requests?direction={direction}&at={at}&state={state}&order={order}&withattributes={withattributes}&withproperties={withproperties}") Call> pullRequests(// @Default("PROJ") @Query("projectkey") String projectKey,// @Default("REPO") @Query("repositoryslug") String repositoryslug,// @Default("INCOMING") @Query("direction") String direction,// @Default("23") @Query("at") String at,// @Default("OPEN") @Query("state") String state,// @Default("NEWEST") @Query("order") String order,// @Default("true") @Query("withattributes") String withattributes,// @Default("true") @Query("withproperties") String withproperties); } 

然后,编译代码时将生成一个构建器,您可以使用默认参数调用它:

 BitBucketServerServicePullRequestsBuilder.pullRequests() .invoke(bitBucketServerService); 

或者设置您喜欢的任何参数:

 BitBucketServerServicePullRequestsBuilder.pullRequests() .withAt("24") .invoke(bitBucketServerService); 

有关GitHub的更多信息: https : //github.com/tomasbjerre/java-method-invocation-builder