2. Recap ...
• Replace Implicit Tree with Composite
(Refactoring to Patterns)
• Refactoring to Composite loosens
coupling to implicit tree
• Builder loosens coupling to Composite
4. Builder (GoF)
• The construction of a complex object is separated from its
representation so that the same construction process can create
different representations
• Builder Defines the required operations for creating various parts of
a product
• ConcreteBuilder Implements the operations declared in the Builder
interface.
• Director Builds a specific product via the interface exposed by the
Builder object.
• Product The concrete type the Builder object creates.
5. Class Diagram 1_1196587101774
TagNode activityTag = new TagNode(“activity”);
...
TagNode flavorsTag = new TagNode(“flavors”);
activityTag.add(favorsTag);
...
TagNode flavorTag = new TagNode(“flavor”);
flavorsTag.add(flavorTag);
Class Diagram 3_1196677789548
TagBuilder builder = new TagBuilder(“activity”);
...
builder.addChild(“flavors”);
...
builder.addToParent(“flavors”, “flavor”);
...
6. Class Diagram 2_1196596929958
Document doc = new DocumentImpl();
Element orderTag = doc.createElement(“order”);
orderTag.setAttribute(“id”, order.getOrderId());
Element productTag = doc.createElement(“product”);
productTag.setAttribute(“id”, product.getID());
Text productName = doc.createTextNode(product.getName());
productTag.appendChild(productName);
orderTag.appendChld(productTag);
Class Diagram 4_1196679481681
DOMBuilder orderBuilder = new DOMBuilder(“order”)
orderBuilder.addAttribute(“id”, order.getOrder());
orderBuilder.addChild(“product”);
orderBuilder.addAttribute(“id”, product.getID());
orderBuilder.adValue(product.getName());
7. • Benefits
Simplifies a client’s code for constructing a Composite
Reduces the repetitive and error-prone nature of
Composite creation
Creates a loose coupling between client and
Composite
Allows for different representations of the
encapsulated Composite or complex object
• Liabilities
May not have the most intention-revealing interface
8. Mechanics
1. Create Builder
2. Make Builder capable of creating children
3. Make Builder capable of setting attributes
on nodes
4. Reflect on interface ... simplify
5. Refactor Composite construction code to
use Builder
10. Step 1.
Create Builder
public class TagBuilderTest ...
public void testBuilderOneNode()
{
String expectedXml = “<flavors/>”;
String actualXml = TagBuilder(“flavors”).toXml();
assertXmlEquals(expectedXml, actualXml);
}
11. Step 1.
Create Builder
public class TagBuilder
{
private TagNode rootNode;
public TagBuilder(String rootTagName)
{
rootNode = new TagNode(rootTagName);
}
public String toXml()
{
return rootNode.toString();
}
}
12. Step 2.
Support child creation and placement
public class TagBuilderTest ...
public void testBuilderOneChild()
{
String expectedXml = “<flavors>” +
“<flavor/>” +
“</flavors>”;
TagBuilder builder = TagBuilder(“flavors”);
builder.addChild(“flavor”);
String actualXml = builder.toXml();
assertXmlEquals(expectedXml, actualXml);
}
13. Step 2.
Support child creation and placement
public class TagBuilder
{
private TagNode rootNode;
private TagNode currentNode;
public TagBuilder(String rootTagName)
{
rootNode = new TagNode(rootTagName);
currentNode = rootNode;
}
pubic void addChild(String childTagName)
{
TagNode parentNode = currentNode;
currentNode = new TagNode(childTagName);
parentNode.addChild(curentNode);
}
...
14. Step 2.
Support child creation and placement
public class TagBuilderTest ...
public void testBuilderOneChild()
{
String expectedXml = “<flavors>” +
“<flavor1/>” +
“<flavor2/>” +
“</flavors>”;
TagBuilder builder = TagBuilder(“flavors”);
builder.addChild(“flavor1”);
builder.addSibling(“flavor2”);
String actualXml = builder.toXml();
assertXmlEquals(expectedXml, actualXml);
}
15. Step 2.
Support child creation and placement
public class TagBuilder ...
pubic void addChild(String childTagName)
{
addTo(currentNode, childTagName);
}
public void addSibling(String siblingTagName)
{
addTo(currentNode.getParent(), siblingTagName);
}
private void addTo(TagNode parentNode, String tagName)
{
currentNode = new TagNode(tagName);
parentNode.addChild(curentNode);
}
...
1. Refactor Composite to support Builder
2. Thirdparty Composite?
16. Step 3.
Support attributes and values
public class TagBuilderTest ...
public void testAttributesAndVaues()
{
String expectedXml = “<flavor name=ʼTest-Driven Developmentʼ>” +
“<requirements>” +
“<requirement type=ʼhardwareʼ>” +
“1 computer for every 2 participants” +
“</requirement>”
“</requirements>” +
“</flavor>”;
TagBuilder builder = TagBuilder(“flavor”);
builder.addAttribute(“name”, “Test-Driven Development”);
builder.addChild(“requirements”);
builder.addToParent(“requirements”, “requirement”);
builder.addAttribute(“type”, “hardware”);
builder.addValue(“1 computer for every 2 participants”);
String actualXml = builder.toXml();
assertXmlEquals(expectedXml, actualXml);
}
17. Step 3.
Support attributes and values
public class TagBuilder ...
pubic void addAttribute(String name, String value)
{
currentNode.addAttribute(name, value);
}
public void addValue(String value)
{
currentNode.addValue(value);
}
...
18. Step 4.
Reflect ...
public class TagBuilder
{
public TagBuilder(String rootTagName) { ... }
public void addChild(String childTagName) { ... }
public void addSibling(String siblingTagName) { ... }
public void addToParent(String parentTagName, String childTagName) { ... }
public void addAttribute(String name, String value) { ... }
public void addValue(String value) { ... }
public String toXml() { ... }
}
19. public class TagBuilder
{
public TagBuilder(String rootTagName) { ... }
public void addChild(String childTagName) { ... }
public void addSibling(String siblingTagName) { ... }
public void addToParent(String parentTagName, String childTagName) { ... }
public void addAttribute(String name, String value);
public void addValue(String value);
public String toXml() { ... }
}
public class TagNode
{
public TagNode(String tagName) { ... }
public void add(TagNode childNode) { ... }
public void addAttribute(String name, String value) { ... }
public void addValue(String value) { ... }
public String toString() { ... }
}
20. Step 5.
Replace Composite construction code
public class CatalogWriter ...
TagNode requirementsTag = new TagNode(“requirements”);
flavorTag.add(requirementsTag);
for (int i = 0; i < requirementsCount; ++i)
{
Requirement requirement = flavor.getRequirements()[i];
TagNode requirementTag = new TagNode(“requirement”);
...
requirementsTag.add(requirementsTag);
}
public class CatalogWriter ...
builder.addChild(“requirements”);
for (int i = 0; i < requirementsCount; ++i)
{
Requirement requirement = flavor.getRequirements()[i];
builder.addToParent(“requirements”, “requirement”);
...
}