7

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

提高方法签名可读性的建议之一是针对四个或更少的参数。建议使用多种技术管理较长的参数列表,其中一种技术如下:

第三种结合前两种技术的技术是将 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 建议的解释是否正确?

4

3 回答 3

2

在我看来,您的构建器类与父类相关联(例如与非静态内部类),并且客户端会像这样使用它:

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();
于 2012-12-21T00:34:26.167 回答
1

我已经使用在要实例化的类中定义的接口对 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();
    }
}
于 2012-12-21T01:42:35.970 回答
0

我创建了Java 方法调用构建器,它在编译时生成调用方法的构建器。它还增加了对 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<BitbucketServerResponse<BitBucketServerPullRequest>> 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

于 2016-06-12T12:18:12.117 回答