Reformat builder pattern - issue #224

This commit is contained in:
Ankur Kaushal
2015-11-01 18:03:29 -05:00
parent e7b6542134
commit 3af06a3a3a
8 changed files with 179 additions and 181 deletions

View File

@ -1,55 +1,55 @@
package com.iluwatar.builder; package com.iluwatar.builder;
import com.iluwatar. builder.Hero.HeroBuilder; import com.iluwatar.builder.Hero.HeroBuilder;
/** /**
* *
* The intention of the Builder pattern is to find a solution to the telescoping * The intention of the Builder pattern is to find a solution to the telescoping constructor
* constructor anti-pattern. The telescoping constructor anti-pattern occurs when the * anti-pattern. The telescoping constructor anti-pattern occurs when the increase of object
* increase of object constructor parameter combination leads to an exponential list * constructor parameter combination leads to an exponential list of constructors. Instead of using
* of constructors. Instead of using numerous constructors, the builder pattern uses * numerous constructors, the builder pattern uses another object, a builder, that receives each
* another object, a builder, that receives each initialization parameter step by step * initialization parameter step by step and then returns the resulting constructed object at once.
* and then returns the resulting constructed object at once.
* <p> * <p>
* The Builder pattern has another benefit. It can be used for objects that contain * The Builder pattern has another benefit. It can be used for objects that contain flat data (html
* flat data (html code, SQL query, X.509 certificate...), that is to say, data that * code, SQL query, X.509 certificate...), that is to say, data that can't be easily edited. This
* can't be easily edited. This type of data cannot be edited step by step and must * type of data cannot be edited step by step and must be edited at once. The best way to construct
* be edited at once. The best way to construct such an object is to use a builder * such an object is to use a builder class.
* class.
* <p> * <p>
* In this example we have the Builder pattern variation as described by Joshua Bloch in * In this example we have the Builder pattern variation as described by Joshua Bloch in Effective
* Effective Java 2nd Edition. * Java 2nd Edition.
* <p> * <p>
* We want to build {@link Hero} objects, but its construction is complex because of the * We want to build {@link Hero} objects, but its construction is complex because of the many
* many parameters needed. To aid the user we introduce {@link HeroBuilder} class. * parameters needed. To aid the user we introduce {@link HeroBuilder} class. {@link HeroBuilder}
* {@link HeroBuilder} takes the minimum parameters to build {@link Hero} object in its * takes the minimum parameters to build {@link Hero} object in its constructor. After that
* constructor. After that additional configuration for the {@link Hero} object can be * additional configuration for the {@link Hero} object can be done using the fluent
* done using the fluent {@link HeroBuilder} interface. When configuration is ready the * {@link HeroBuilder} interface. When configuration is ready the build method is called to receive
* build method is called to receive the final {@link Hero} object. * the final {@link Hero} object.
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args command line args
public static void main(String[] args) { */
public static void main(String[] args) {
Hero mage = new HeroBuilder(Profession.MAGE, "Riobard") Hero mage =
.withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER) new HeroBuilder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK)
.build(); .withWeapon(Weapon.DAGGER).build();
System.out.println(mage); System.out.println(mage);
Hero warrior = new HeroBuilder(Profession.WARRIOR, "Amberjill") Hero warrior =
.withHairColor(HairColor.BLOND) new HeroBuilder(Profession.WARRIOR, "Amberjill").withHairColor(HairColor.BLOND)
.withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL) .withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD)
.withWeapon(Weapon.SWORD).build(); .build();
System.out.println(warrior); System.out.println(warrior);
Hero thief = new HeroBuilder(Profession.THIEF, "Desmond") Hero thief =
.withHairType(HairType.BALD).withWeapon(Weapon.BOW).build(); new HeroBuilder(Profession.THIEF, "Desmond").withHairType(HairType.BALD)
System.out.println(thief); .withWeapon(Weapon.BOW).build();
System.out.println(thief);
} }
} }

View File

@ -7,16 +7,16 @@ package com.iluwatar.builder;
*/ */
public enum Armor { public enum Armor {
CLOTHES("clothes"), LEATHER("leather"), CHAIN_MAIL("chain mail"), PLATE_MAIL("plate mail"); CLOTHES("clothes"), LEATHER("leather"), CHAIN_MAIL("chain mail"), PLATE_MAIL("plate mail");
private String title; private String title;
Armor(String title) { Armor(String title) {
this.title = title; this.title = title;
} }
@Override @Override
public String toString() { public String toString() {
return title; return title;
} }
} }

View File

@ -7,11 +7,11 @@ package com.iluwatar.builder;
*/ */
public enum HairColor { public enum HairColor {
WHITE, BLOND, RED, BROWN, BLACK; WHITE, BLOND, RED, BROWN, BLACK;
@Override @Override
public String toString() { public String toString() {
return name().toLowerCase(); return name().toLowerCase();
} }
} }

View File

@ -7,16 +7,17 @@ package com.iluwatar.builder;
*/ */
public enum HairType { public enum HairType {
BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY("long curly"); BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY(
"long curly");
private String title; private String title;
HairType(String title) { HairType(String title) {
this.title = title; this.title = title;
} }
@Override @Override
public String toString() { public String toString() {
return title; return title;
} }
} }

View File

@ -7,123 +7,122 @@ package com.iluwatar.builder;
*/ */
public class Hero { public class Hero {
private final Profession profession; private final Profession profession;
private final String name; private final String name;
private final HairType hairType; private final HairType hairType;
private final HairColor hairColor; private final HairColor hairColor;
private final Armor armor; private final Armor armor;
private final Weapon weapon; private final Weapon weapon;
public Profession getProfession() { public Profession getProfession() {
return profession; return profession;
} }
public String getName() { public String getName() {
return name; return name;
} }
public HairType getHairType() { public HairType getHairType() {
return hairType; return hairType;
} }
public HairColor getHairColor() { public HairColor getHairColor() {
return hairColor; return hairColor;
} }
public Armor getArmor() { public Armor getArmor() {
return armor; return armor;
} }
public Weapon getWeapon() { public Weapon getWeapon() {
return weapon; return weapon;
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("This is a "); sb.append("This is a ");
sb.append(profession); sb.append(profession);
sb.append(" named "); sb.append(" named ");
sb.append(name); sb.append(name);
if (hairColor != null || hairType != null) { if (hairColor != null || hairType != null) {
sb.append(" with "); sb.append(" with ");
if (hairColor != null) { if (hairColor != null) {
sb.append(hairColor); sb.append(hairColor);
sb.append(" "); sb.append(" ");
} }
if (hairType != null) { if (hairType != null) {
sb.append(hairType); sb.append(hairType);
sb.append(" "); sb.append(" ");
} }
sb.append(hairType != HairType.BALD ? "hair" : "head"); sb.append(hairType != HairType.BALD ? "hair" : "head");
} }
if (armor != null) { if (armor != null) {
sb.append(" wearing "); sb.append(" wearing ");
sb.append(armor); sb.append(armor);
} }
if (weapon != null) { if (weapon != null) {
sb.append(" and wielding a "); sb.append(" and wielding a ");
sb.append(weapon); sb.append(weapon);
} }
sb.append("."); sb.append(".");
return sb.toString(); return sb.toString();
} }
private Hero(HeroBuilder builder) { private Hero(HeroBuilder builder) {
this.profession = builder.profession; this.profession = builder.profession;
this.name = builder.name; this.name = builder.name;
this.hairColor = builder.hairColor; this.hairColor = builder.hairColor;
this.hairType = builder.hairType; this.hairType = builder.hairType;
this.weapon = builder.weapon; this.weapon = builder.weapon;
this.armor = builder.armor; this.armor = builder.armor;
} }
/** /**
* *
* The builder class. * The builder class.
* *
*/ */
public static class HeroBuilder { public static class HeroBuilder {
private final Profession profession; private final Profession profession;
private final String name; private final String name;
private HairType hairType; private HairType hairType;
private HairColor hairColor; private HairColor hairColor;
private Armor armor; private Armor armor;
private Weapon weapon; private Weapon weapon;
public HeroBuilder(Profession profession, String name) { public HeroBuilder(Profession profession, String name) {
if (profession == null || name == null) { if (profession == null || name == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException("profession and name can not be null");
"profession and name can not be null"); }
} this.profession = profession;
this.profession = profession; this.name = name;
this.name = name; }
}
public HeroBuilder withHairType(HairType hairType) { public HeroBuilder withHairType(HairType hairType) {
this.hairType = hairType; this.hairType = hairType;
return this; return this;
} }
public HeroBuilder withHairColor(HairColor hairColor) { public HeroBuilder withHairColor(HairColor hairColor) {
this.hairColor = hairColor; this.hairColor = hairColor;
return this; return this;
} }
public HeroBuilder withArmor(Armor armor) { public HeroBuilder withArmor(Armor armor) {
this.armor = armor; this.armor = armor;
return this; return this;
} }
public HeroBuilder withWeapon(Weapon weapon) { public HeroBuilder withWeapon(Weapon weapon) {
this.weapon = weapon; this.weapon = weapon;
return this; return this;
} }
public Hero build() { public Hero build() {
return new Hero(this); return new Hero(this);
} }
} }
} }

View File

@ -7,11 +7,10 @@ package com.iluwatar.builder;
*/ */
public enum Profession { public enum Profession {
WARRIOR, THIEF, MAGE, PRIEST; WARRIOR, THIEF, MAGE, PRIEST;
@Override
public String toString() {
return name().toLowerCase();
}
@Override
public String toString() {
return name().toLowerCase();
}
} }

View File

@ -7,11 +7,10 @@ package com.iluwatar.builder;
*/ */
public enum Weapon { public enum Weapon {
DAGGER, SWORD, AXE, WARHAMMER, BOW; DAGGER, SWORD, AXE, WARHAMMER, BOW;
@Override
public String toString() {
return name().toLowerCase();
}
@Override
public String toString() {
return name().toLowerCase();
}
} }

View File

@ -2,7 +2,7 @@ package com.iluwatar.builder;
import org.junit.Test; import org.junit.Test;
import com.iluwatar. builder.App; import com.iluwatar.builder.App;
/** /**
* *
@ -11,9 +11,9 @@ import com.iluwatar. builder.App;
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }