Design Patterns: The Composite Pattern in Java
by Riley MacDonald, October 25, 2017

The composite design pattern is used to “compose” objects into tree structure type hierarchies. Clients are then able to uniformly view objects and compositions. These hierarchies are comprised of two types of objects called “composites” and “leafs”. Composites are tree structures that can contain other composites or leafs. Leafs are “single objects” that cannot contain children (composites). Composites and leafs implement (extend) the same Component abstract class making it easier for clients to traverse the collections.

Example Implementation
This example uses classes named Parent and Child. Both of these classes implement (extend) the FamilyComponent abstract class. Parent represents a composite node while Child represents a leaf node. A parent can have many children. A parent can also have children who are also parents; and so on. This example doesn’t take into consideration that these objects may change over time (for example when a child becomes a parent).

FamilyComponent abstract class
FamilyComponent contains several methods. In this example the method requestPermission() is specific to Child and the grantPermission() method is specific to Parent. The default implementation of these methods is UnsopportedOperationException because if one of the implementations doesn’t support an operation method (like requestPermission() or grantPermission()) they just inherit the default implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class FamilyComponent {
    // "Composite" Methods
    public void add(FamilyComponent familyComponent) {
        throw new UnsupportedOperationException();
    }
    public void remove(FamilyComponent familyComponent) {
        throw new UnsupportedOperationException();
    }
    public FamilyComponent getChild(int i) {
        throw new UnsupportedOperationException();
    }
 
    // Operation methods
    public String getName() {
        throw new UnsupportedOperationException();
    }
    public void print() {
        throw new UnsupportedOperationException();
    }
    // Children need to ask for permission before performing some tasks
    public void requestPermission() {
        throw new UnsupportedOperationException();
    }
    // Parents need to grant permission to children when they request it
    public boolean grantPermission() {
        throw new UnsupportedOperationException();
    }
}

The Child Implementation
Here’s the child implementation, it’s quite straightforward. The operation method print() prints the name of the child. Since this is a leaf node it doesn’t need to override any of the “composite” methods from FamilyComponent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Child extends FamilyComponent {
    String name;
 
    public Child(String name) {
        this.name = name;
    }
 
    @Override
    public String getName() {
        return name;
    }
 
    @Override
    public void requestPermission() {
        // ask for permission
    }
 
    @Override
    public void print() {
        System.out.println(String.format("Name: %s", name));
    }
}

The Parent Implementation
The Parent implementation has a bit more to it. Since it can have children or parents (any implementation of FamilyComponent) it must implement all of the “composite” methods from the abstract FamilyComponent class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Parent extends FamilyComponent {
    ArrayList<FamilyComponent> familyComponents = new ArrayList<>();
 
    String name;
 
    public Parent(String name) {
        this.name = name;
    }
 
    @Override
    public void add(FamilyComponent familyComponent) {
        familyComponent.add(familyComponent);
    }
 
    @Override
    public void remove(FamilyComponent familyComponent) {
        familyComponent.remove(familyComponent);
    }
 
    @Override
    public FamilyComponent getChild(int i) {
        return familyComponents.get(i);
    }
 
    @Override
    public String getName() {
        return name;
    }
 
    @Override
    public boolean grantPermission() {
        return false; // No, you can't do that.
    }
 
    @Override
    public void print() {
        System.out.println(String.format("Name: %s", name));
        // What's the best way to loop over all the possible children/parents here for this object?
    }
}

The Iterator Pattern
Notice the comment “What’s the best way to loop over all the possible children/parents here for this object?”. We could just loop over the collection familyComponents and invoke print() but we won’t see print() invoked on any of the “compsite” objects. My last design pattern post was implementing the iterator pattern in java. The composite and iterator patterns work well together. Let’s use the iterator pattern to implement the print() method for Parent. First let’s add a new method to the FamilyComponent abstract class which will be responsible for creating the iterator.

1
2
3
public Iterator<FamilyComponent> createIterator() {
    throw new UnsupportedOperationException();
};

The Parent implementation of createIterator():

1
2
3
4
5
6
7
8
@Override
public Iterator<FamilyComponent> createIterator() {
    if (iterator == null) {
        iterator = new FamilyCompositeIterator(familyComponents.iterator());
    }
 
    return iterator;
}

FamilyCompositeIterator
The FamilyCompositeIterator is a new class which can handle iterating over any composite. The iterator peek()s at the top of the stack and determines if it should have a look inside or pop() it from the stack and move on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class FamilyCompositeIterator implements Iterator {
    final Stack<Iterator<FamilyComponent>> stack = new Stack<>();
 
    public FamilyCompositeIterator(Iterator iterator) {
        stack.push(iterator);
    }
 
    @Override
    public boolean hasNext() {
        if (stack.isEmpty()) {
            return false;
        } else {
            Iterator<FamilyComponent> iterator = stack.peek();
            if (!iterator.hasNext()) {
                stack.pop();
                return hasNext();
            } else {
                return true;
            }
        }
    }
 
    @Override
    public Object next() {
        if (hasNext()) {
            Iterator<FamilyComponent> iterator = stack.peek();
            FamilyComponent familyComponent = iterator.next();
 
            stack.push(familyComponent.createIterator());
 
            return familyComponent;
        } else {
            return null;
        }
    }
}

The Child implementation of createIterator():

1
2
3
4
    @Override
    public Iterator<FamilyComponent> createIterator() {
        return new NullIterator();
    }

NullIterator
The NullIterator class does the opposite of FamilyCompositeIterator. It just indicates that there’s “nothing to see here, move along”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class NullIterator implements Iterator {
    @Override
    public boolean hasNext() {
        return false;
    }
 
    @Override
    public Object next() {
        return null;
    }
 
    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}

The Parent print() method implementation
Now that we have implementations of createIterator(), FamilyCompositeIterator and NullIterator we can finish the print() implementation of the Parent class.

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void print() {
    System.out.println(String.format("Name: %s", name));
 
    FamilyCompositeIterator iterator =
            new FamilyCompositeIterator(familyComponents.iterator());
 
    while (iterator.hasNext()) {
        FamilyComponent component = (FamilyComponent) iterator.next();
        component.print();
    }
}

Summary
Clients can now invoke a single method to traverse over these objects without knowing the internal details. The composite pattern is great for managing and traversing hierarchies of data such as in this example. The composite pattern allows individual objects and compositions of objects to be treated uniformly.

Open questions / concerns
I’m not completely sure about Parents implementation of the print() method, more specifically if I should be casting FamilyComponent from Object. I also left out the remove() method in FamilyCompositeIterator(). I’m not exactly sure how the implementation should look. I’m also seeing some unchecked assignment warnings in my IDE that I’m not sure about.

Open the comment form

Leave a comment:

Comments will be reviewed before they are posted.

User Comments:

My Design Patterns Catalog - Riley MacDonald on 2017-12-04 23:50:57 said:
[…] Composite: The composite design pattern is used to “compose” objects into tree structure type hierarchies. […]