Tuesday, April 18, 2017

Composite Design Pattern in Java

INTRODUCTION

  • The Composite Design pattern is categorized under Structural Patterns.
  • It helps to traverse the Tree Structured object and perform the operations on it. In the tree structure, a node which contains no child called Leaf Object and a node which contains at least one child called Composite Object.
  • The client will treat both composite object and simple object as same. Example, double clicking the folder and file will be same but the operation performed in different Objects.
  • In this pattern, accessing of an object’s behavior follows the recursion principle if it contains multiple children.

EXAMPLE

Following are the examples from Java API.
  1. add(Component comp) method of java.awt.Container class.
  2. In Collection Framework
    1. addAll(Collection<? extends E> c) method of java.util.List interface.
    2. addAll(Collection<? extends E> c) method of java.util.Set interface.
    3. putAll(Map<? extends K,? extends V> m) method of java.util.Map interface.

WHEN TO USE?

The composite design pattern can be used when
  1. You want to handle the part-whole hierarchies of the object, i.e an objects which may have children or without children (tree-structured objects). part denotes the individual object and whole denotes the composite object.
  2. If the client didn’t want to know the difference between the composite object and simple object.

USECASE

Assembling the car. A Car will consist multiple components and those components may be an individual component or again it may be assembled with multiple individual components.
Car assembling may have below processes.
  1. Assembling Engine
  2. Assembling Body - It may have sub-processes like
  1. Assembling Front Body
  2. Assembling Center Body
  3. Assembling Back Body
  1. Assembling Wheel - It may have sub-processes like
  1. Assembling Tyre
  2. Assembling Chassis
Below the tree representation of whole assembling process.
Leaf Objects - Engine, Front, Center, Back, Tyre and Chassis
Composite Objects - Car, Body, and Wheel

ENTITIES

Composite Design pattern contains the following entities.
  1. Component - It is an interface consist of all the functionality of the both composite and simple objects.
  2. Composite - Composite represents an object which should have at least one child object. It also performs the child operations so that when a composite object is accessed, it also gives the result of all it’s children.
  3. Leaf - Leaf represents an object which has zero children.
  4. Client - who will access the Component and manipulates the Composite object or individual object

IMPLEMENTATION

Define Component

First, create an interface(CarComponent.java)which represents the Component Object.
public interface CarComponent {
 String getName();

 long getPrice();

 void assembly();

 void addComponent(CarComponent component);

 void removeComponent(CarComponent component);
}

Implement the Leaf Object

A Leaf object is the one has no children for it. So create a class (Engine.java) which will implement all the components behaviors.
public class Engine implements CarComponent {

 @Override
 public String getName() {
   return "Engine";
 }

 @Override
 public long getPrice() {
   return 50000;
 }

 @Override
 public void assembly() {
   System.out.println("Engine - Assembly DONE");
 }

 @Override
 public void addComponent(CarComponent component) {
   // no components to add
 }

 @Override
 public void removeComponent(CarComponent component) {
   // no components to remove
 }

}

Implement the Composite Object

In the above example, the assembling of wheel contains the subprocess, so create another class (Wheel.java) which represents the Composite object and also has the child operations.
import java.util.ArrayList;
import java.util.List;

public class Wheel implements CarComponent {

 private List<CarComponent> wheelComponents = new ArrayList<>();

 public Wheel() {
   this.addComponent(new Tyre());
   this.addComponent(new Chassis());
 }

 @Override
 public String getName() {
   return "Wheel";
 }

 @Override
 public long getPrice() {
   long price = 0;

   for (CarComponent component : wheelComponents) {
     System.out.println(component.getName() + " Price " + component.getPrice());
     price = price + component.getPrice();
   }

   return price;
 }

 @Override
 public void assembly() {
   for (CarComponent component : wheelComponents) {
     component.assembly();
     System.out.println(component.getName() + " - Assembly DONE");
   }

   System.out.println("Wheel - Assembly DONE");
 }

 @Override
 public void addComponent(CarComponent component) {
   this.wheelComponents.add(component);
 }

 @Override
 public void removeComponent(CarComponent component) {
   // no components to remove
 }

}

Here, getPrice() & assembly() methods contains the child operations. So it produces the final result of all the children operations.

Now, implement the children objects, child 1 (Tyre.java) & child 2 (Chassis.java) has no children.
public class Tyre implements CarComponent {

 @Override
 public String getName() {
   return "Tyre";
 }

 @Override
 public long getPrice() {
   return 20000;
 }

 @Override
 public void assembly() {
   // no assembly operation here
 }

 @Override
 public void addComponent(CarComponent component) {
   // no components to add
 }

 @Override
 public void removeComponent(CarComponent component) {
   // no components to remove
 }

}

Now create a Client(CompositePatternClient.java) which will access the Component and also performs the operations on either Composite Object or Individual Object.
public class CompositePatternClient {

 public static void main(String[] args) {
   Engine engine = new Engine();
   Wheel wheel = new Wheel();

   System.out.println("...Car Assembly...");
   engine.assembly();
   wheel.assembly();

   System.out.println("\n...Car Price...");
   long enginePrice = engine.getPrice();
   long wheelPrice = wheel.getPrice();
   System.out.println("Wheel Price(Tyre + Chassis): " + wheelPrice);
   System.out.println("Engine Price: " + enginePrice);
   System.out.println("Total Price: " + (enginePrice + wheelPrice));
 }
}

OUTPUT


...Car Assembly...
Engine - Assembly DONE
Tyre - Assembly DONE
Chassis - Assembly DONE
Wheel - Assembly DONE

...Car Price...
Tyre Price 20000
Chassis Price 30000
Wheel Price(Tyre + Chassis): 50000
Engine Price: 50000
Total Price: 100000
Hope this example clarifies the Composite Design Pattern. Please share your comments and suggestions below.
Happy Knowledge Sharing!!!

No comments :

Post a Comment