diff --git a/README.md b/README.md index 377cad846..3ae006ff8 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Creational design patterns abstract the instantiation process. They help make a * [Prototype](#prototype) * [Property](#property) * [Singleton](#singleton) +* [Step Builder](#step-builder) * [Multiton](#multiton) * [Object Pool](#object-pool) @@ -181,6 +182,14 @@ A programming idiom is a means of expressing a recurring construct in one or mor **Real world examples:** * [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29) +## Step Builder [↑](#list-of-design-patterns) +**Intent:** An extension of the Builder pattern that fully guides the user through the creation of the object with no chances of confusion. +The user experience will be much more improved by the fact that he will only see the next step methods available, NO build method until is the right time to build the object. + +![alt text](./step-builder/etc/step-builder.png "Step Builder") + +**Applicability:** Use the Step Builder pattern when the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled the construction process must allow different representations for the object that's constructed when in the process of constructing the order is important. + ## Adapter [↑](#list-of-design-patterns) **Intent:** Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. diff --git a/pom.xml b/pom.xml index 13105f139..1059edc58 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,7 @@ async-method-invocation business-delegate half-sync-half-async + step-builder diff --git a/step-builder/etc/step-builder.png b/step-builder/etc/step-builder.png new file mode 100644 index 000000000..b7b623657 Binary files /dev/null and b/step-builder/etc/step-builder.png differ diff --git a/step-builder/etc/step-builder.ucls b/step-builder/etc/step-builder.ucls new file mode 100644 index 000000000..bb3560a2e --- /dev/null +++ b/step-builder/etc/step-builder.ucls @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/step-builder/pom.xml b/step-builder/pom.xml new file mode 100644 index 000000000..8466266a7 --- /dev/null +++ b/step-builder/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + java-design-patterns + com.iluwatar + 1.5.0 + + step-builder + + + junit + junit + test + + + \ No newline at end of file diff --git a/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java b/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java new file mode 100644 index 000000000..439c5bd11 --- /dev/null +++ b/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java @@ -0,0 +1,69 @@ +package com.iluwatar.stepbuilder; + +/** + * Step Builder Pattern + * + *

Intent + *
+ * An extension of the Builder pattern that fully guides the user + * through the creation of the object with no chances of confusion. + *
+ * The user experience will be much more improved by the fact that + * he will only see the next step methods available, NO build method + * until is the right time to build the object. + * + *

Implementation + *
+ *

+ * + *

Applicability + *
+ * Use the Step Builder pattern when the algorithm for creating a + * complex object should be independent of the parts that make up + * the object and how they're assembled the construction process must + * allow different representations for the object that's constructed + * when in the process of constructing the order is important. + * + * http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html + */ +public class App { + public static void main(String[] args) { + + Character warrior = CharacterStepBuilder.newBuilder() + .name("Amberjill") + .fighterClass("Paladin") + .withWeapon("Sword") + .noAbilities() + .build(); + + System.out.println(warrior); + + Character mage = CharacterStepBuilder.newBuilder() + .name("Riobard") + .wizardClass("Sorcerer") + .withSpell("Fireball") + .withAbility("Fire Aura") + .withAbility("Teleport") + .noMoreAbilities() + .build(); + + System.out.println(mage); + + Character thief = CharacterStepBuilder.newBuilder() + .name("Desmond") + .fighterClass("Rogue") + .noWeapon() + .build(); + + System.out.println(thief); + } +} diff --git a/step-builder/src/main/java/com/iluwatar/stepbuilder/Character.java b/step-builder/src/main/java/com/iluwatar/stepbuilder/Character.java new file mode 100644 index 000000000..4bd29227f --- /dev/null +++ b/step-builder/src/main/java/com/iluwatar/stepbuilder/Character.java @@ -0,0 +1,82 @@ +package com.iluwatar.stepbuilder; + +import java.util.List; + +/** + * The class with many parameters. + */ +public class Character { + + private String name; + private String fighterClass; + private String wizardClass; + private String weapon; + private String spell; + private List abilities; + + public Character(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFighterClass() { + return fighterClass; + } + + public void setFighterClass(String fighterClass) { + this.fighterClass = fighterClass; + } + + public String getWizardClass() { + return wizardClass; + } + + public void setWizardClass(String wizardClass) { + this.wizardClass = wizardClass; + } + + public String getWeapon() { + return weapon; + } + + public void setWeapon(String weapon) { + this.weapon = weapon; + } + + public String getSpell() { + return spell; + } + + public void setSpell(String spell) { + this.spell = spell; + } + + public List getAbilities() { + return abilities; + } + + public void setAbilities(List abilities) { + this.abilities = abilities; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("This is a "); + sb.append(fighterClass != null ? fighterClass : wizardClass); + sb.append(" named a "); + sb.append(name); + sb.append(" armed "); + sb.append(weapon != null ? weapon : spell != null ? spell : "with nothing"); + sb.append(abilities != null ? (" and wielding " + abilities + " abilities") : ""); + sb.append("."); + return sb.toString(); + } +} diff --git a/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java b/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java new file mode 100644 index 000000000..e042758d9 --- /dev/null +++ b/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java @@ -0,0 +1,168 @@ +package com.iluwatar.stepbuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * The Step Builder class. + */ + +public class CharacterStepBuilder { + + private CharacterStepBuilder() { + } + + public static NameStep newBuilder() { + return new CharacterSteps(); + } + + /** + * First Builder Step in charge of the Character name. + * Next Step available : ClassStep + */ + public interface NameStep { + ClassStep name(String name); + } + + /** + * This step is in charge of setting the Character class (fighter or wizard). + * Fighter choice : Next Step available : WeaponStep + * Wizard choice : Next Step available : SpellStep + */ + public interface ClassStep { + WeaponStep fighterClass(String fighterClass); + SpellStep wizardClass(String wizardClass); + } + + /** + * This step is in charge of the weapon. + * Weapon choice : Next Step available : AbilityStep + * No weapon choice : Next Step available : BuildStep + */ + public interface WeaponStep { + AbilityStep withWeapon(String weapon); + BuildStep noWeapon(); + } + + /** + * This step is in charge of the spell. + * Spell choice : Next Step available : AbilityStep + * No spell choice : Next Step available : BuildStep + */ + public interface SpellStep { + AbilityStep withSpell(String spell); + BuildStep noSpell(); + } + + /** + * This step is in charge of abilities. + * Next Step available : BuildStep + */ + public interface AbilityStep { + AbilityStep withAbility(String ability); + BuildStep noMoreAbilities(); + BuildStep noAbilities(); + } + + /** + * This is the final step in charge of building the Character Object. + * Validation should be here. + */ + public interface BuildStep { + Character build(); + } + + + /** + * Step Builder implementation. + */ + private static class CharacterSteps + implements NameStep, ClassStep, WeaponStep, SpellStep, AbilityStep, BuildStep { + + private String name; + private String fighterClass; + private String wizardClass; + private String weapon; + private String spell; + private List abilities = new ArrayList<>(); + + @Override + public ClassStep name(String name) { + this.name = name; + return this; + } + + @Override + public WeaponStep fighterClass(String fighterClass) { + this.fighterClass = fighterClass; + return this; + } + + @Override + public SpellStep wizardClass(String wizardClass) { + this.wizardClass = wizardClass; + return this; + } + + @Override + public AbilityStep withWeapon(String weapon) { + this.weapon = weapon; + return this; + } + + @Override + public BuildStep noWeapon() { + return this; + } + + @Override + public AbilityStep withSpell(String spell) { + this.spell = spell; + return this; + } + + @Override + public BuildStep noSpell() { + return this; + } + + @Override + public AbilityStep withAbility(String ability) { + this.abilities.add(ability); + return this; + } + + @Override + public BuildStep noMoreAbilities() { + return this; + } + + @Override + public BuildStep noAbilities() { + return this; + } + + @Override + public Character build() { + Character character = new Character(name); + + if (fighterClass != null) { + character.setFighterClass(fighterClass); + } else { + character.setWizardClass(wizardClass); + } + + if (weapon != null) { + character.setWeapon(weapon); + } else { + character.setSpell(spell); + } + + if (!abilities.isEmpty()) { + character.setAbilities(abilities); + } + + return character; + } + } +} diff --git a/step-builder/src/test/java/com/iluwatar/stepbuilder/AppTest.java b/step-builder/src/test/java/com/iluwatar/stepbuilder/AppTest.java new file mode 100644 index 000000000..61fe82aaf --- /dev/null +++ b/step-builder/src/test/java/com/iluwatar/stepbuilder/AppTest.java @@ -0,0 +1,12 @@ +package com.iluwatar.stepbuilder; + +import org.junit.Test; + +public class AppTest { + + @Test + public void test() { + String[] args = {}; + App.main(args); + } +}