Created
October 21, 2013 07:06
-
-
Save sandermak/7079734 to your computer and use it in GitHub Desktop.
Second alternative to the standard Builder pattern implementation in Java. Also see blogpost at http://branchandbound.net/blog/java/2013/10/failed-experiment-improving-builder-pattern/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.branchandbound.builder; | |
public class PizzaOrderNewStyle { | |
private int size; | |
private boolean pepperoni; | |
private boolean chicken; | |
private boolean mushroom; | |
private boolean peppers; | |
private String cheese; | |
private String sauce; | |
private String orderFor; | |
private PizzaOrderNewStyle() { | |
// Prevent direct instantiation | |
} | |
public static Builder pizzaOrder(int size, String sauce, String orderFor) { | |
return new PizzaOrderNewStyle.Builder(size, sauce, orderFor); | |
} | |
public static class Builder { | |
private PizzaOrderNewStyle pizza = new PizzaOrderNewStyle(); | |
public Builder(int size, String sauce, String orderFor) { | |
pizza.size = size; | |
pizza.sauce = sauce; | |
pizza.orderFor = orderFor; | |
} | |
public Builder withPepperoni() { | |
pizza.pepperoni = true; | |
return this; | |
} | |
public Builder withChicken() { | |
pizza.chicken = true; | |
return this; | |
} | |
public Builder withMushroom() { | |
pizza.mushroom = true; | |
return this; | |
} | |
public Builder withPeppers() { | |
pizza.peppers = true; | |
return this; | |
} | |
public Builder withCheese(String _cheese) { | |
pizza.cheese = _cheese; | |
return this; | |
} | |
public PizzaOrderNewStyle build() { | |
try { | |
return pizza; | |
} | |
finally { | |
// Invalidate this builder | |
pizza = null; | |
} | |
} | |
} | |
public int getSize() { | |
return size; | |
} | |
public boolean isPepperoni() { | |
return pepperoni; | |
} | |
public boolean isChicken() { | |
return chicken; | |
} | |
public boolean isMushroom() { | |
return mushroom; | |
} | |
public boolean isPeppers() { | |
return peppers; | |
} | |
public String getCheese() { | |
return cheese; | |
} | |
public String getSauce() { | |
return sauce; | |
} | |
public String getOrderFor() { | |
return orderFor; | |
} | |
@Override | |
public int hashCode() { | |
final int prime = 31; | |
int result = 1; | |
result = prime * result + ((cheese == null) ? 0 : cheese.hashCode()); | |
result = prime * result + (chicken ? 1231 : 1237); | |
result = prime * result + (mushroom ? 1231 : 1237); | |
result = prime * result + ((orderFor == null) ? 0 : orderFor.hashCode()); | |
result = prime * result + (pepperoni ? 1231 : 1237); | |
result = prime * result + (peppers ? 1231 : 1237); | |
result = prime * result + ((sauce == null) ? 0 : sauce.hashCode()); | |
result = prime * result + size; | |
return result; | |
} | |
@Override | |
public boolean equals(Object obj) { | |
if (this == obj) | |
return true; | |
if (obj == null) | |
return false; | |
if (getClass() != obj.getClass()) | |
return false; | |
PizzaOrderNewStyle other = (PizzaOrderNewStyle) obj; | |
if (cheese == null) { | |
if (other.cheese != null) | |
return false; | |
} else if (!cheese.equals(other.cheese)) | |
return false; | |
if (chicken != other.chicken) | |
return false; | |
if (mushroom != other.mushroom) | |
return false; | |
if (orderFor == null) { | |
if (other.orderFor != null) | |
return false; | |
} else if (!orderFor.equals(other.orderFor)) | |
return false; | |
if (pepperoni != other.pepperoni) | |
return false; | |
if (peppers != other.peppers) | |
return false; | |
if (sauce == null) { | |
if (other.sauce != null) | |
return false; | |
} else if (!sauce.equals(other.sauce)) | |
return false; | |
if (size != other.size) | |
return false; | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.branchandbound.builder.test; | |
import static net.branchandbound.builder.PizzaOrderNewStyle.pizzaOrder; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertNotNull; | |
import static org.junit.Assert.assertNull; | |
import static org.junit.Assert.assertTrue; | |
import net.branchandbound.builder.PizzaOrderNewStyle; | |
import net.branchandbound.builder.PizzaOrderNewStyle.Builder; | |
import org.junit.Test; | |
public class PizzaOrderNewStyleTest { | |
@Test | |
public void valuesShouldBeRetained() { | |
PizzaOrderNewStyle pizzaOrder = | |
pizzaOrder(10, "tomato", "Sander").withPepperoni().withMushroom() | |
.withCheese("parmesan").build(); | |
assertEquals(10, pizzaOrder.getSize()); | |
assertEquals("tomato", pizzaOrder.getSauce()); | |
assertEquals("Sander", pizzaOrder.getOrderFor()); | |
assertTrue(pizzaOrder.isPepperoni()); | |
assertFalse(pizzaOrder.isChicken()); | |
assertTrue(pizzaOrder.isMushroom()); | |
assertFalse(pizzaOrder.isPeppers()); | |
assertEquals("parmesan", pizzaOrder.getCheese()); | |
} | |
@Test | |
public void testEqualsHashCode() { | |
PizzaOrderNewStyle a = getCorrectlyFilledBuilder().build(); | |
PizzaOrderNewStyle b = getCorrectlyFilledBuilder().build(); | |
assertEquals(a, b); | |
assertEquals(a.hashCode(), b.hashCode()); | |
} | |
@Test | |
public void cannotBuildTwice() { | |
Builder builder = getCorrectlyFilledBuilder(); | |
assertNotNull(builder.build()); | |
assertNull(builder.build()); | |
} | |
@Test(expected = NullPointerException.class) | |
public void cannotUseBuilderAfterBuild() { | |
Builder correctlyFilledBuilder = getCorrectlyFilledBuilder(); | |
correctlyFilledBuilder.build(); | |
correctlyFilledBuilder.withCheese("FAIL"); | |
} | |
private Builder getCorrectlyFilledBuilder() { | |
return pizzaOrder(10, "tomato", "Sander").withPepperoni().withMushroom() | |
.withCheese("parmesan"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment