aboutsummaryrefslogtreecommitdiff
path: root/value/userguide/builders-howto.md
diff options
context:
space:
mode:
Diffstat (limited to 'value/userguide/builders-howto.md')
-rw-r--r--value/userguide/builders-howto.md86
1 files changed, 75 insertions, 11 deletions
diff --git a/value/userguide/builders-howto.md b/value/userguide/builders-howto.md
index e7cf5373..3ff89468 100644
--- a/value/userguide/builders-howto.md
+++ b/value/userguide/builders-howto.md
@@ -154,7 +154,7 @@ public abstract class Animal {
abstract Builder toBuilder();
- public Animal withName(String name) {
+ public final Animal withName(String name) {
return toBuilder().setName(name).build();
}
@@ -201,7 +201,7 @@ public abstract class Animal {
abstract Animal autoBuild(); // not public
- public Animal build() {
+ public final Animal build() {
Animal animal = autoBuild();
Preconditions.checkState(animal.numberOfLegs() >= 0, "Negative legs");
return animal;
@@ -235,7 +235,7 @@ public abstract class Animal {
abstract Animal autoBuild(); // not public
- public Animal build() {
+ public final Animal build() {
setName(name().toLowerCase());
return autoBuild();
}
@@ -279,8 +279,8 @@ public abstract class Animal {
abstract Animal autoBuild(); // not public
- public Animal build() {
- if (!name().isPresent()) {
+ public final Animal build() {
+ if (name().isEmpty()) {
setName(numberOfLegs() + "-legged creature");
}
return autoBuild();
@@ -491,7 +491,7 @@ public abstract class Animal {
public abstract Builder setNumberOfLegs(int value);
abstract ImmutableSet.Builder<String> countriesBuilder();
- public Builder addCountry(String value) {
+ public final Builder addCountry(String value) {
countriesBuilder().add(value);
return this;
}
@@ -623,11 +623,75 @@ in an exception because the required properties of `Species` have not been set.
A [_step builder_](http://rdafbn.blogspot.com/2012/07/step-builder-pattern_28.html)
is a collection of builder interfaces that take you step by step through the
-setting of each of a list of required properties. We think that these are a nice
-idea in principle but not necessarily in practice. Regardless, if you want to
-use AutoValue to implement a step builder,
-[this example](https://github.com/google/auto/issues/1000#issuecomment-792875738)
-shows you how.
+setting of each of a list of required properties. This means you can be sure at
+compile time that all the properties are set before you build, at the expense of
+some extra code and a bit less flexibility.
+
+Here is an example:
+
+```java
+@AutoValue
+public abstract class Stepped {
+ public abstract String foo();
+ public abstract String bar();
+ public abstract int baz();
+
+ public static FooStep builder() {
+ return new AutoValue_Stepped.Builder();
+ }
+
+ public interface FooStep {
+ BarStep setFoo(String foo);
+ }
+
+ public interface BarStep {
+ BazStep setBar(String bar);
+ }
+
+ public interface BazStep {
+ Build setBaz(int baz);
+ }
+
+ public interface Build {
+ Stepped build();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder implements FooStep, BarStep, BazStep, Build {}
+}
+```
+
+It might be used like this:
+
+```java
+Stepped stepped = Stepped.builder().setFoo("foo").setBar("bar").setBaz(3).build();
+```
+
+The idea is that the only way to build an instance of `Stepped`
+is to go through the steps imposed by the `FooStep`, `BarStep`, and
+`BazStep` interfaces to set the properties in order, with a final build step.
+
+Once you have set the `baz` property there is nothing else to do except build,
+so you could also combine the `setBaz` and `build` methods like this:
+
+```java
+ ...
+
+ public interface BazStep {
+ Stepped setBazAndBuild(int baz);
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder implements FooStep, BarStep, BazStep {
+ abstract Builder setBaz(int baz);
+ abstract Stepped build();
+
+ @Override
+ public Stepped setBazAndBuild(int baz) {
+ return setBaz(baz).build();
+ }
+ }
+```
## <a name="autobuilder"></a> ... create a builder for something other than an `@AutoValue`?