Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step builder? #1000

Closed
clinuxrulz opened this issue Mar 8, 2021 · 2 comments · Fixed by #1003
Closed

Step builder? #1000

clinuxrulz opened this issue Mar 8, 2021 · 2 comments · Fixed by #1003
Assignees

Comments

@clinuxrulz
Copy link

clinuxrulz commented Mar 8, 2021

Just curious why the step builder is not used in order to ensure all fields are set at compile time rather than runtime.

Reference:
https://medium.com/@castigliego/step-builder-pattern-3bcac4eaf9e8

@eamonnmcmanus
Copy link
Member

The Step Builder pattern is interesting but brings its own constraints. You have to set properties in a particular order, or have a combinatorial explosion of interfaces. Even then, the number of step interfaces increases with the number of properties. Having said that, it's entirely possible to have the same @AutoValue.Builder class implement all the step interfaces but only expose the steps in the public API:

@AutoValue
public abstract class Stepped {
  public abstract String one();
  public abstract String two();
  public abstract int three();

  public static OneStep builder() {
    return new AutoValue_Stepped.Builder();
  }

  public interface OneStep {
    TwoStep setOne(String one);
  }

  public interface TwoStep {
    ThreeStep setTwo(String two);
  }

  public interface ThreeStep {
    Stepped setThreeAndBuild(int three);
  }

  @AutoValue.Builder
  abstract static class Builder implements OneStep, TwoStep, ThreeStep {
    @Override public abstract Builder setOne(String one);
    @Override public abstract Builder setTwo(String two);
    abstract Builder setThree(int three);
    abstract Stepped build();

    @Override public Stepped setThreeAndBuild(int three) {
      return setThree(three).build();
    }
  }
}

The Builder class is not public, so client code from outside the package has to go through the step interfaces to build an object.

The final step, which produces the built object, has to work slightly differently, since the set method doesn't return a builder instance but the built object. So it can't be called setThree, but that would arguably be confusing anyway.

I think it would be reasonable for us to document this.

@eamonnmcmanus eamonnmcmanus self-assigned this Mar 8, 2021
copybara-service bot pushed a commit that referenced this issue Mar 8, 2021
Fixes #1000.

RELNOTES=n/a
PiperOrigin-RevId: 361653279
@clinuxrulz
Copy link
Author

Thank you very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants