#111 Implementation of Step Builder pattern

This commit is contained in:
Dmitriy Zarubin
2015-08-07 16:17:47 +03:00
parent 3dc6b81962
commit f52d7d3dbc
9 changed files with 541 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="true" nesting-relationships="false">
<interface id="1" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder.SpellStep"
project="step-builder" file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="301" y="280"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="2" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder.CharacterSteps"
project="step-builder" file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="95" y="345"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder" project="step-builder"
file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="92" y="56"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="4" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder.AbilityStep"
project="step-builder" file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="409" y="418"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<interface id="5" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder.ClassStep"
project="step-builder" file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="406" y="163"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<interface id="6" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder.WeaponStep"
project="step-builder" file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="509" y="279"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<interface id="7" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder.NameStep" project="step-builder"
file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="404" y="49"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<interface id="8" language="java" name="com.iluwatar.stepbuilder.CharacterStepBuilder.BuildStep"
project="step-builder" file="/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="412" y="550"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="9" language="java" name="com.iluwatar.stepbuilder.Character" project="step-builder"
file="/step-builder/src/main/java/com/iluwatar/stepbuilder/Character.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="710" y="217"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<realization id="10">
<bendpoint x="252" y="168"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="5"/>
</realization>
<realization id="11">
<bendpoint x="255" y="419"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="4"/>
</realization>
<realization id="12">
<bendpoint x="197" y="123"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="7"/>
</realization>
<dependency id="13">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="7"/>
</dependency>
<dependency id="14">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="1"/>
</dependency>
<realization id="15">
<bendpoint x="398" y="346"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="6"/>
</realization>
<dependency id="16">
<end type="SOURCE" refId="7"/>
<end type="TARGET" refId="5"/>
</dependency>
<realization id="17">
<bendpoint x="261" y="554"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="8"/>
</realization>
<dependency id="18">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="2"/>
</dependency>
<dependency id="19">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="4"/>
</dependency>
<dependency id="20">
<bendpoint x="512" y="477"/>
<end type="SOURCE" refId="6"/>
<end type="TARGET" refId="8"/>
</dependency>
<dependency id="21">
<end type="SOURCE" refId="4"/>
<end type="TARGET" refId="8"/>
</dependency>
<realization id="22">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="1"/>
</realization>
<dependency id="23">
<bendpoint x="597" y="547"/>
<end type="SOURCE" refId="8"/>
<end type="TARGET" refId="9"/>
</dependency>
<dependency id="24">
<bendpoint x="97" y="602"/>
<bendpoint x="712" y="596"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="9"/>
</dependency>
<dependency id="25">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="6"/>
</dependency>
<dependency id="26">
<end type="SOURCE" refId="6"/>
<end type="TARGET" refId="4"/>
</dependency>
<dependency id="27">
<bendpoint x="303" y="475"/>
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="8"/>
</dependency>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

19
step-builder/pom.xml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.5.0</version>
</parent>
<artifactId>step-builder</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,69 @@
package com.iluwatar.stepbuilder;
/**
* Step Builder Pattern
*
* <p><b>Intent</b>
* <br/>
* An extension of the Builder pattern that fully guides the user
* through the creation of the object with no chances of confusion.
* <br/>
* 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.
*
* <p><b>Implementation</b>
* </br>
* <ul>The concept is simple:
*
* <li>Write creational steps inner classes or interfaces where each
* method knows what can be displayed next.</li>
*
* <li>Implement all your steps interfaces in an inner static class.</li>
*
* <li>Last step is the BuildStep, in charge of creating the object
* you need to build.</li>
* </ul>
*
* <p><b>Applicability</b>
* <br/>
* 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);
}
}

View File

@ -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<String> 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<String> getAbilities() {
return abilities;
}
public void setAbilities(List<String> 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();
}
}

View File

@ -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<String> 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;
}
}
}

View File

@ -0,0 +1,12 @@
package com.iluwatar.stepbuilder;
import org.junit.Test;
public class AppTest {
@Test
public void test() {
String[] args = {};
App.main(args);
}
}