tl  tr
  Home | Tutorials | Articles | Videos | Products | Tools | Search
Interviews | Open Source | Tag Cloud | Follow Us | Bookmark | Contact   
 Design Patterns > Java Design Patterns > Composite

Composite 

Composite pattern comes under Structural design pattern. It composes objects into tree structures to represent part-whole hierarchies. Nodes of tree structure are accessed uniformly irrespective of whether its a leaf nodes or branch (composite) node.

Behaviour & Advantages

  • Treats compositions and individual objects in a similar manner.
  • It forms a kind of one to many relationship where the container node has relation to one or more child nodes. The child node may be a container node or leave node. A branch with no children is treated as leave node and each branch ends with leave nodes.
Participants
  • Component
    Abstract interface for all components (both Composite and Leave components). Declares an interface for accessing the elements of composition (child components) and optionally parent component.
  • Leaf
    It has no children and represents leave objects in the composition.
  • Composite
    It acts as a container for child components and holds a reference. The child component can be a Composite or Leaf component.
  • Client
    One who operates on composite structure through the Component interface.

This example shows programming knowledge categorized in a tree hierarchy. Here IKnowledge interface acts as Component, Topic class acts as Leaf and TopicContainer acts as Composite components.

The Knowledge Component is shown below,

File Name  :  
com/bethecoder/tutorials/dp/composite/IKnowledge.java 
   
package com.bethecoder.tutorials.dp.composite;

import java.util.Iterator;

public interface IKnowledge {

  /**
   * Get Current Topic Name
   */
  public String getTopicName();
  
  /**
   * Get Parent Topic if any otherwise null
   */
  public IKnowledge getParentTopic();

  /**
   * Set Parent Topic
   */
  public void setParentTopic(IKnowledge parentTopic);

  /**
   * Get subtopics of current topic 
   */
  public Iterator<IKnowledge> getSubTopics();
}
   

As Topic is the Leaf Component it doesn't provide any API to add subtopics.

File Name  :  
com/bethecoder/tutorials/dp/composite/Topic.java 
   
package com.bethecoder.tutorials.dp.composite;

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

public class Topic implements IKnowledge {

  /**
   * Topic name, parent topic and subtopics.
   */
  protected String topicName;
  protected IKnowledge parentTopic;
  protected List<IKnowledge> subTopics = new ArrayList<IKnowledge>(0);

  public Topic(String topicName) {
    this.topicName = topicName;
  }
  
  @Override
  public IKnowledge getParentTopic() {
    return parentTopic;
  }

  @Override
  public Iterator<IKnowledge> getSubTopics() {
    return subTopics.iterator();
  }

  @Override
  public String getTopicName() {
    return topicName;
  }

  public void setTopicName(String topicName) {
    this.topicName = topicName;
  }

  public void setParentTopic(IKnowledge parentTopic) {
    this.parentTopic = parentTopic;
  }

}
   

Topic Container Composite Component provides addSubTopic method to add sub topics.

File Name  :  
com/bethecoder/tutorials/dp/composite/TopicContainer.java 
   
package com.bethecoder.tutorials.dp.composite;


public class TopicContainer extends Topic implements IKnowledge {

  public TopicContainer(String topicName) {
    super(topicName);
  }

  /**
   * Provide an interface to add sub topics.
   */
  public void addSubTopic(IKnowledge subTopic) {
    subTopic.setParentTopic(this);
    this.subTopics.add(subTopic);
  }

}
   

Composite pattern usage is shown below,

File Name  :  
com/bethecoder/tutorials/dp/composite/Test.java 
   
package com.bethecoder.tutorials.dp.composite;

import java.util.Iterator;

public class Test {

  /**
   @param args
   */
  public static void main(String[] args) {
    TopicContainer progLanguages = new TopicContainer("Programming Languages");
    TopicContainer java = new TopicContainer("JAVA");
    TopicContainer cpp = new TopicContainer("CPP");
    TopicContainer spring = new TopicContainer("Spring");
    TopicContainer springMVC = new TopicContainer("Spring MVC");

    java.addSubTopic(new Topic("Struts2"));
    java.addSubTopic(spring);
    java.addSubTopic(new Topic("Hibernate"));
    
    spring.addSubTopic(new Topic("Spring Core"));
    spring.addSubTopic(springMVC);
    
    springMVC.addSubTopic(new Topic("Controllers"));
    springMVC.addSubTopic(new Topic("View Resolvers"));
    
    cpp.addSubTopic(new Topic("Pointers"));
    cpp.addSubTopic(new Topic("Virtual Functions"));
    
    progLanguages.addSubTopic(java);
    progLanguages.addSubTopic(cpp);
    
    /**
     * Traverse the nodes in tree hierarchy
     */
    traverse(progLanguages);
  }

  private static void traverse(IKnowledge topic) {
    System.out.println(getPrefix(topic+ topic.getTopicName());
    
    //Iterate sub topics
    Iterator<IKnowledge> subTopics = topic.getSubTopics();
    while (subTopics.hasNext()) {
      traverse(subTopics.next());
    }
  }
  
  private static String getPrefix(IKnowledge topic) {
    
    if (topic.getParentTopic() == null) {
      return "|-";
    }
    
    String prefix = "|";
    while (topic.getParentTopic() != null) {
      
      if (isLastTopic(topic.getParentTopic())) {
        prefix = "   " + prefix;
      else {
        prefix = "|  " + prefix;
      }
      topic = topic.getParentTopic();
    }
    
    prefix = (prefix+ "\n" + prefix"-";
    return prefix;
  }
  
  private static boolean isLastTopic(IKnowledge topic) {
    if (topic.getParentTopic() == null) {
      return true;
    }
    
    Iterator<IKnowledge> subTopics = topic.getParentTopic().getSubTopics();
    int topicCnt = 0;
    int foundIndex = -1;
    
    while (subTopics.hasNext()) {
      topicCnt++;
      
      if (subTopics.next().equals(topic)) {
        foundIndex = topicCnt;
      }
    }
    
    return foundIndex == topicCnt;
  }
}
   

It gives the following output,
|-Programming Languages
   |
   |-JAVA
   |  |
   |  |-Struts2
   |  |
   |  |-Spring
   |  |  |
   |  |  |-Spring Core
   |  |  |
   |  |  |-Spring MVC
   |  |     |
   |  |     |-Controllers
   |  |     |
   |  |     |-View Resolvers
   |  |
   |  |-Hibernate
   |
   |-CPP
      |
      |-Pointers
      |
      |-Virtual Functions



 
  


  
bl  br