#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

View File

@ -27,6 +27,7 @@ Creational design patterns abstract the instantiation process. They help make a
* [Prototype](#prototype) * [Prototype](#prototype)
* [Property](#property) * [Property](#property)
* [Singleton](#singleton) * [Singleton](#singleton)
* [Step Builder](#step-builder)
* [Multiton](#multiton) * [Multiton](#multiton)
* [Object Pool](#object-pool) * [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:** **Real world examples:**
* [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29) * [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
## <a name="step-builder">Step Builder</a> [&#8593;](#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.
## <a name="adapter">Adapter</a> [&#8593;](#list-of-design-patterns) ## <a name="adapter">Adapter</a> [&#8593;](#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. **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.

View File

@ -73,6 +73,7 @@
<module>async-method-invocation</module> <module>async-method-invocation</module>
<module>business-delegate</module> <module>business-delegate</module>
<module>half-sync-half-async</module> <module>half-sync-half-async</module>
<module>step-builder</module>
</modules> </modules>
<dependencyManagement> <dependencyManagement>

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);
}
}