Composite Design Pattern

The Composite Design pattern is a structural pattern that defines a way to access a group of objects through a single object. It can be though of as a tree structure where a node holds reference to its children. The main actors in these pattern are

  • Node

    The Node defines an interface that each object in the hierarchy implements. The node can be a composite (contains other nodes) or leaf (does not contain other nodes)

  • Composite Node

    A composite node maintains a reference to a list of child nodes. The composite node could itself be a child node(contains a parent) or can be a root node(does not have a parent)

  • Leaf Node

    A Leaf node cannot contain any children. It can be a specialized node such that it stores only specific values (e.g. TextNode to store only text)

Example
To Demonstrate the composite pattern we develop an interface that can act as both a parent as well as leaf node.

The Node interfaces defines the method to help the Ojbect act as a leaf as well as a parent.

package com.studytrails.patters.java.composite;

import java.util.List;

/**
 * The Node Interface that defines the contract for a leaf as well as a parent.
 */
public interface Node {

	/**
	 * If the node has no children then it is a leaf
	 */
	boolean isLeaf();

	/**
	 * If the node has not children then return false. This has the same purpose
	 * as isLeaf and is provided just for usability. Its ok to have only one
	 * method though.
	 * 
	 * @return
	 */
	boolean hasChildren();

	/**
	 * Get the list of children.
	 * 
	 * @return
	 */
	List getChildren();

	/**
	 * The parent of the current node
	 * 
	 * @return parent node
	 */
	Node getParent();

	/**
	 * adds child
	 * 
	 * @param child
	 * @return the added child or null if the current node is a leaf.
	 */
	Node addChild(Node child);

	/**
	 * When a child is added to a node the parent field of the child is set to
	 * the node to which it is added. helps in traversing the trees both ways.
	 * 
	 * @param parent
	 */
	void setParent(Node parent);

	/**
	 * the name of the node.
	 * 
	 * @return
	 */
	String getName();

}
						
						
					
					
					
					
					
					
     

The Implementation class for the Node inteface

package com.studytrails.patters.java.composite;

import java.util.ArrayList;
import java.util.List;

public class NodeImpl implements Node {

	List children = new ArrayList();
	Node parent = null;
	String name = null;
	
	public NodeImpl(String name) {
		this.name = name;
	}

	@Override
	public boolean isLeaf() {
		if (children.size() > 0)
			return false;
		return true;
	}

	@Override
	public boolean hasChildren() {
		return !isLeaf();
	}

	@Override
	public List getChildren() {
		return children;
	}

	@Override
	public Node getParent() {
		return parent == null ? null : parent;
	}

	@Override
	public Node addChild(Node n) {
		if (n != null) {
			children.add(n);
			n.setParent(this);
		}
		return n;

	}

	@Override
	public void setParent(Node parent) {
		this.parent = parent;

	}

	@Override
	public String getName() {
		return name;
	}


}
					
					
					
					
					
					
					
					
     

The TextNode is a specialized node such that it can store only String values and cannot act as a parent.

package com.studytrails.patters.java.composite;

import java.util.ArrayList;
import java.util.List;

public class NodeImpl implements Node {

	List children = new ArrayList();
	Node parent = null;
	String name = null;
	
	public NodeImpl(String name) {
		this.name = name;
	}

	@Override
	public boolean isLeaf() {
		if (children.size() > 0)
			return false;
		return true;
	}

	@Override
	public boolean hasChildren() {
		return !isLeaf();
	}

	@Override
	public List getChildren() {
		return children;
	}

	@Override
	public Node getParent() {
		return parent == null ? null : parent;
	}

	@Override
	public Node addChild(Node n) {
		if (n != null) {
			children.add(n);
			n.setParent(this);
		}
		return n;

	}

	@Override
	public void setParent(Node parent) {
		this.parent = parent;

	}

	@Override
	public String getName() {
		return name;
	}


}


					
					
					
					
					
					
     

The Client demonstrates the creation of a tree structure using the Node interface.

package com.studytrails.patters.java.composite;

public class Client {

	private static Node root;
	private static TextNode text1;
	private static TextNode b;
	private static Node a;

	public static void main(String[] args) {
		// create the root node
		root = new NodeImpl("root");

		// create another node.
		a = new NodeImpl("a");

		// create text node
		text1 = new TextNode("text1");
		text1.setValue("value1");

		// another text node
		b = new TextNode("text2");
		b.setValue("value2");

		// a is a composite node and is added as a child to the root node
		root.addChild(a);
		// add the text node as child to the "a" node
		a.addChild(text1);

		// add the b node as child of root
		root.addChild(b);

		// prints null since b is a leaf node and not a composite node
		System.out.println(b.addChild(new TextNode("test")));
		// return false
		System.out.println(b.hasChildren());
		// b's parent is root.
		System.out.println(b.getParent().getName());

	}
}

This is the class diagram of the Composite pattern

Composite Design Pattern

Composite pattern is used widely in JSON and XML processing. The composite pattern is ideal in representing a hierarchical document model.

In our example we have a special implementation for the leaf node. However, the leaf node can be another composite node and a specialization is not always required.

The main advantage of composite pattern is that the client can treat the whole hierarchy as a single object and traverse through the tree using the same definition for each node.

What are some of the important considerations

  • In our example we treated the leaf node separately, we can instead treat the composite node separately. The advantage then is that we dont have to maintain the list of Children in the leaf nodes.
  • Deleting a child can be tricky especially if it is not a leaf node.
  • This pattern generally does not have a child that refers to mulitple parents.

This finishes our tutorial on the composite pattern. Its a useful pattern if you have a whole part relationship or a tree kind of structure.

One thought on “Composite Design Pattern

  • September 12, 2017 at 12:44 pm
    Permalink

    TextNode code is wrong! Duplicated with NodeImpl.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.