Skip to content

Instantly share code, notes, and snippets.

@michael-simons
Created July 13, 2016 07:37
Show Gist options
  • Save michael-simons/1f9a6ae42f78b2a024b84e0248dd74c6 to your computer and use it in GitHub Desktop.
Save michael-simons/1f9a6ae42f78b2a024b84e0248dd74c6 to your computer and use it in GitHub Desktop.
package patternexamples;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
public class Sandwich {
private final String bread;
private final String meat;
private final String cheese;
private final List<String> vegetables;
private Sandwich(Builder builder) {
this.bread = builder.bread;
this.meat = builder.meat;
this.cheese = builder.cheese;
this.vegetables = Collections.unmodifiableList(builder.vegetables);
}
public String getBread() {
return bread;
}
public String getCheese() {
return cheese;
}
public String getMeat() {
return meat;
}
public List<String> getVegetables() {
return vegetables;
}
public Sandwich withAdditionalVeggies(final String vegetable) {
return new Builder(this).addVeggie(vegetable).close().create();
}
public Sandwich withCheese(final String cheese) {
return new Builder(this).withCheese(cheese).noVeggies().create();
}
public Sandwich removeCheese() {
return new Builder(this).noCheese().close().create();
}
public static interface ChooseBreadStep {
public ChooseMeatStep withMeat(final String meat);
public AddVeggiesStep vegan();
}
public static interface ChooseMeatStep {
public ChooseCheeseStep withCheese(final String cheese);
public AddVeggiesStep noCheese();
}
public static interface ChooseCheeseStep {
public AddVeggiesStep addVeggie(final String vegetable);
public CloseStep noVeggies();
}
public static interface AddVeggiesStep {
public AddVeggiesStep addVeggie(final String vegetable);
public CloseStep close();
}
public static interface CloseStep {
public Sandwich create();
}
private static class Builder implements ChooseBreadStep, ChooseMeatStep, ChooseCheeseStep, AddVeggiesStep, CloseStep {
final String bread;
String meat;
String cheese;
final List<String> vegetables = new ArrayList<>();
Builder(String bread) {
this.bread = bread;
}
Builder(Sandwich template) {
this.bread = template.bread;
this.meat = template.meat;
this.cheese = template.cheese;
this.vegetables.addAll(template.vegetables);
}
@Override
public ChooseMeatStep withMeat(String meat) {
this.meat = meat;
return this;
}
@Override
public AddVeggiesStep vegan() {
return this;
}
@Override
public ChooseCheeseStep withCheese(String cheese) {
this.cheese = cheese;
return this;
}
@Override
public AddVeggiesStep noCheese() {
this.cheese = null;
return this;
}
@Override
public AddVeggiesStep addVeggie(String vegetable) {
this.vegetables.add(vegetable);
return this;
}
@Override
public CloseStep noVeggies() {
return this;
}
@Override
public CloseStep close() {
return this;
}
@Override
public Sandwich create() {
return new Sandwich(this);
}
}
public static Sandwich make(String bread, Function<ChooseBreadStep, CloseStep> configuration) {
return configuration.andThen(CloseStep::create).apply(new Builder(bread));
}
public static void main(final String...a) {
Sandwich.make("white", cfg -> cfg
.withMeat("parma")
.withCheese("cheedar")
.addVeggie("salad")
.close()
);
Sandwich.make("brown", cfg -> cfg
.withMeat("salami")
.noCheese()
.close());
Sandwich.make("spelt", cfg -> cfg
.vegan()
.addVeggie("salad")
.addVeggie("gherkins")
.addVeggie("tomatoes")
.close()
);
Sandwich sandwich = Sandwich.make("white", cfg -> cfg
.withMeat("parma")
.withCheese("cheedar")
.addVeggie("salad")
.close()
);
sandwich = sandwich.removeCheese();
assert(sandwich.meat.equals("parma") && sandwich.cheese == null && sandwich.vegetables.size() == 1);
sandwich = sandwich
.withAdditionalVeggies("tomatoes")
.withCheese("gouda");
assert(sandwich.meat.equals("parma") && sandwich.cheese.equals("gouda") && sandwich.vegetables.size() == 2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment