Extract Composite Refactoring
Extract Composite - Refactoring to a Pattern
Refactoring existing code so that it improves and conforms to a design pattern can be a good thing. Your code will be easier to understand since it follows a known ‘pattern’. Of course you have to need the change - your code will probably be uncomfortable to read and be crying out for clarification.
This refactoring is about implementing a one to many relationship in your code more clearly by refactoring to the Composite design pattern.
Presentation
UML - Before and After
Here is the situation before and after the refactoring, in hand drawn UML.
UML Before

The problem with the “before” situation is:
- The child looping logic is duplicated twice - once in the
FormTagclass and again in theLinkTagclass. And we all know that code duplication is evil and hard to maintain.
By refactoring, we remove the code duplication to a common base class.
UML After

The solution:
- We use the “extract composite” refactoring to put the common looping behaviour in the display() method of a common composite class.
- We make the existing classes subclasses of this new composite class.
Code - Before and After
Here is a python example of the above refactoring. Note that the display() method is actually called toPlainTextString() in this example.
Code Before
# Before
class Node(object):
def __init__(self, name):
self.name = name
def toPlainTextString(self):
return self.name
class FormTag(Node):
def __init__(self):
self.allNodesVector = []
def toPlainTextString(self):
result = ""
for node in self.allNodesVector:
result += node.toPlainTextString()
return result
class LinkTag(Node):
def __init__(self):
self.linkData = []
def toPlainTextString(self):
result = ""
for node in self.linkData:
result += node.toPlainTextString()
return result
f = FormTag()
f.allNodesVector.append(Node("a"))
f.allNodesVector.append(Node("b"))
f.allNodesVector.append(Node("c"))
l = LinkTag()
l.linkData += [Node("x"), Node("y"), Node("z")]
print f.toPlainTextString()
print l.toPlainTextString()
Then we apply the following steps…
- Create a Composite Class - compile
- Make each child container (a class in the hierarchy that contains duplicate child-handling code) a subclass of your composite - compile
- For each method with duplicated looping code
- Move & rename the child reference field UP to the composite using “Pull Up Field”
- Move the method UP to the composite using “Pull Up Method”
- Pull up any relevant constructor code too.
- Check interfaces so that client code using the old composites still works.
Code After
# After
class Node(object):
def __init__(self, name):
self.name = name
def toPlainTextString(self):
return self.name
class Composite(Node):
def __init__(self):
self.children = []
def toPlainTextString(self):
result = ""
for node in self.children:
result += node.toPlainTextString()
return result
class FormTag(Composite):
pass
class LinkTag(Composite):
pass
f = FormTag()
f.children.append(Node("a"))
f.children.append(Node("b"))
f.children.append(Node("c"))
l = LinkTag()
l.children += [Node("x"), Node("y"), Node("z")]
print f.toPlainTextString()
print l.toPlainTextString()
Does the refactoring break anything?
A proper refactoring means you don’t break anything and everything behaves as before.
python before.py
abc
xyz
python after.py
abc
xyz
Confirmed - we get the same output in both cases. :-)