提交 a95bd31b 编写于 作者: I Ilkka Seppälä

Merge pull request #194 from dmitz/step-builder

#111 Implementation of Step Builder pattern
......@@ -32,6 +32,7 @@ system independent of how its objects are created, composed, and represented.
* [Prototype](#prototype)
* [Property](#property)
* [Singleton](#singleton)
* [Step Builder](#step-builder)
* [Multiton](#multiton)
* [Object Pool](#object-pool)
......@@ -206,6 +207,14 @@ access to it.
**Real world examples:**
* [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)
**Intent:** Convert the interface of a class into another interface the clients
expect. Adapter lets classes work together that couldn't otherwise because of
......@@ -1008,6 +1017,7 @@ other words, version numbers are used only for project planning sake.
* [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420)
* [Spring Data](http://www.amazon.com/Spring-Data-Mark-Pollack/dp/1449323952/ref=sr_1_1)
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
* [Marco Castigliego - Step Builder](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html)
# License
......
......@@ -73,6 +73,7 @@
<module>async-method-invocation</module>
<module>business-delegate</module>
<module>half-sync-half-async</module>
<module>step-builder</module>
</modules>
<dependencyManagement>
......
<?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>
\ No newline at end of file
<?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>
\ No newline at end of file
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);
}
}
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 ");
sb.append(name);
sb.append(" armed with a ");
sb.append(weapon != null ? weapon : spell != null ? spell : "with nothing");
sb.append(abilities != null ? (" and wielding " + abilities + " abilities") : "");
sb.append(".");
return sb.toString();
}
}
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;
}
}
}
package com.iluwatar.stepbuilder;
import org.junit.Test;
public class AppTest {
@Test
public void test() {
String[] args = {};
App.main(args);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册