Showing posts with label Composite Pattern. Show all posts
Showing posts with label Composite Pattern. Show all posts

Saturday, 12 October 2013

Composite Design Pattern - Implementation

Master Practical Java Architecture & Design Patterns!

Subscribe to Ram N Java for clean coding tutorials, GoF design patterns, and real-world system implementations!

🔔 Subscribe to Ram N Java

The Challenge of Tree Structures & Hierarchies

In software development, systems frequently model part-whole hierarchies such as file system directories, organizational management trees, or complex graphical UI components.

Without a clean architectural approach, client code is forced to distinguish between leaf nodes (individual items) and branches (composite groups containing child items). This requires repetitive type-checking conditionals (instanceof checks) and separate logic paths throughout your application, making the codebase rigid and brittle.

Hands-On Implementation Architecture

The Composite Design Pattern solves this challenge by letting clients treat individual objects and compositions of objects uniformly:

  • Component: An abstract class or interface declaring common operations (e.g., showDetails()) for both simple and complex objects in the hierarchy.
  • Leaf: Represents individual building blocks with no child nodes. A Leaf implements the Component interface directly to perform specific work.
  • Composite: Represents branch nodes that hold a collection of child Components. It implements child management methods (add(), remove()) and delegates operations recursively to its children.
  • Client: Interacts with all elements strictly through the common Component interface, completely oblivious to whether it is operating on a single leaf or an entire subtree.

Key Architectural Benefits

Implementing the Composite pattern brings substantial design advantages:

  • Uniform Client Code: Clients treat individual primitives and complex object trees identically without writing type-checking logic.
  • Open/Closed Principle: Introducing new leaf or composite component types requires no changes to existing classes or client code.
  • Recursive Simplicity: Operations propagate down tree structures effortlessly via clean recursive calls.

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=HM1Zn-uVF60

Click the below Image to Enlarge

Composite Design Pattern - Implementation

Composite Design Pattern - Implementation - Class Diagram

























IEmployee.java

public interface IEmployee
{
public int getYearlySalary();

}

Employee.java

import java.util.ArrayList;

// Employee class is the Composite node [i.e. it can have other objects below it]

public class Employee implements IEmployee
{

private String               name;
private int                  monthlySalary;
// Employee designation Can be CEO,Dev Manager,QA Manager,Dev TeamLead,QA TeamLead
private String               designation;

private ArrayList<IEmployee> subordinateList = new ArrayList<IEmployee>();

public Employee( String name, int monthlySalary, String designation )
{
super();
this.name = name;
this.monthlySalary = monthlySalary;
this.designation = designation;
}

public String getName()
{
return name;
}

public void setName( String name )
{
this.name = name;
}

public int getMonthlySalary()
{
return monthlySalary;
}

public void setMonthlySalary( int monthlySalary )
{
this.monthlySalary = monthlySalary;
}

public String getDesignation()
{
return designation;
}

public void setDesignation( String designation )
{
this.designation = designation;
}

public ArrayList<IEmployee> getSubordinateList()
{
return subordinateList;
}

public void setSubordinateList( ArrayList<IEmployee> subordinateList )
{
this.subordinateList = subordinateList;
}

@Override
public int getYearlySalary()
{
return monthlySalary * 12;
}

public void addSubordinate( IEmployee employee )
{
subordinateList.add(employee);
}

public void removeSubordinate( IEmployee employee )
{
subordinateList.remove(employee);
}

public ArrayList<IEmployee> getChilds()
{
return getSubordinateList();
}

}


SoftwareEngineer.java

// SoftwareEngineer class is the Leaf node [i.e. it cann't have other objects below it]

public class SoftwareEngineer implements IEmployee
{
private String name;
private int    monthlySalary;
// Employee designation Can be Dev Software Engineer, QA Software Engineer
private String designation;

public SoftwareEngineer( String name, int monthlySalary, String designation )
{
super();
this.name = name;
this.monthlySalary = monthlySalary;
this.designation = designation;
}

public String getName()
{
return name;
}

public void setName( String name )
{
this.name = name;
}

public int getMonthlySalary()
{
return monthlySalary;
}

public void setMonthlySalary( int monthlySalary )
{
this.monthlySalary = monthlySalary;
}

public String getDesignation()
{
return designation;
}

public void setDesignation( String designation )
{
this.designation = designation;
}

@Override
public int getYearlySalary()
{
return monthlySalary * 12;
}

}


CompositePatternDemo.java

import java.util.ArrayList;

public class CompositePatternDemo
{

public static void main( String[] args )
{
Employee dave = new Employee("Dave", 200000, "CEO");

Employee peter = new Employee("peter", 100000, "Dev Manager");
Employee john = new Employee("John", 100000, "QA Manager");

Employee rohan = new Employee("Rohan", 50000, "Dev TeamLead");
Employee vijay = new Employee("Vijay", 50000, "QA TeamLead");

SoftwareEngineer raj = new SoftwareEngineer("Raj", 30000, "Dev Software Engineer");
SoftwareEngineer mohan = new SoftwareEngineer("Mohan", 30000, "Dev Software Engineer");
SoftwareEngineer hema = new SoftwareEngineer("Hema", 30000, "Dev Software Engineer");

SoftwareEngineer saran = new SoftwareEngineer("Saran", 20000, "QA Software Engineer");
SoftwareEngineer riya = new SoftwareEngineer("Riya", 20000, "QA Software Engineer");

dave.addSubordinate(peter);
dave.addSubordinate(john);

peter.addSubordinate(rohan);
john.addSubordinate(vijay);

rohan.addSubordinate(raj);
rohan.addSubordinate(mohan);
rohan.addSubordinate(hema);

vijay.addSubordinate(saran);
vijay.addSubordinate(riya);


getSubOrdinates(dave);
getSubOrdinates(peter);
getSubOrdinates(john);
getSubOrdinates(rohan);
getSubOrdinates(vijay);
getSubOrdinates(raj);
getSubOrdinates(mohan);
getSubOrdinates(hema);
getSubOrdinates(saran);
getSubOrdinates(riya);
}

private static void getSubOrdinates( IEmployee iemployee )
{
if( iemployee instanceof Employee )
{
Employee employee = (Employee) iemployee;
System.out.println("\n------------- SubordinatesListOf "+ employee.getName() +" : "+employee.getDesignation() + " ---------------------------------\n");
ArrayList<IEmployee> subordinatesListOfDave = employee.getChilds();
for( IEmployee iEmployee : subordinatesListOfDave )
{
if( iEmployee instanceof Employee )
{
Employee employeeObj = (Employee) iEmployee;
System.out.println(employeeObj.getName() + " : " + employeeObj.getDesignation() + ":"
               + employeeObj.getMonthlySalary() + ":" + employeeObj.getYearlySalary());
}
else
{
SoftwareEngineer softwareEngineer = (SoftwareEngineer) iEmployee;
System.out.println(softwareEngineer.getName() + " : "
               + softwareEngineer.getDesignation() + ":"
               + softwareEngineer.getMonthlySalary() + ":"
               + softwareEngineer.getYearlySalary());

}

}
}
else
{
System.out.println("\n--------------------------------------------------------------------------------------");
SoftwareEngineer softwareEngineer = (SoftwareEngineer) iemployee;
System.out.println("\nNo Subordinates for "+softwareEngineer.getName()+" : "+softwareEngineer.getDesignation()
+" : "+softwareEngineer.getMonthlySalary()+" : "+softwareEngineer.getYearlySalary());
}
}

}


Output

------------- SubordinatesListOf Dave : CEO ---------------------------------

peter : Dev Manager:100000:1200000
John : QA Manager:100000:1200000

------------- SubordinatesListOf peter : Dev Manager ---------------------------------

Rohan : Dev TeamLead:50000:600000

------------- SubordinatesListOf John : QA Manager ---------------------------------

Vijay : QA TeamLead:50000:600000

------------- SubordinatesListOf Rohan : Dev TeamLead ---------------------------------

Raj : Dev Software Engineer:30000:360000
Mohan : Dev Software Engineer:30000:360000
Hema : Dev Software Engineer:30000:360000

------------- SubordinatesListOf Vijay : QA TeamLead ---------------------------------

Saran : QA Software Engineer:20000:240000
Riya : QA Software Engineer:20000:240000

--------------------------------------------------------------------------------------

No Subordinates for Raj : Dev Software Engineer : 30000 : 360000

--------------------------------------------------------------------------------------

No Subordinates for Mohan : Dev Software Engineer : 30000 : 360000

--------------------------------------------------------------------------------------

No Subordinates for Hema : Dev Software Engineer : 30000 : 360000

--------------------------------------------------------------------------------------

No Subordinates for Saran : QA Software Engineer : 20000 : 240000

--------------------------------------------------------------------------------------

No Subordinates for Riya : QA Software Engineer : 20000 : 240000

Composite Design Pattern – Key Points

Master Core Java Architecture & Design Patterns!

Subscribe to Ram N Java for clean code principles, GoF design patterns, and step-by-step software engineering tutorials!

🔔 Subscribe to Ram N Java

Core Summary of the Composite Design Pattern

The Composite Design Pattern is a structural design pattern cataloged by the Gang of Four (GoF) that allows you to compose objects into tree structures to represent part-whole hierarchies.

The defining feature of the Composite pattern is that it lets clients treat individual objects (leaf nodes) and compositions of objects (containers or branches) uniformly. This eliminates the need for clients to perform cumbersome type checks before executing operations.

Essential Architectural Takeaways

Keep these critical points and principles in mind when evaluating or applying the Composite pattern:

  • Component Contract: A common abstraction (interface or abstract class) defining standard operations that can be performed on both simple and complex elements in the tree.
  • Leaf vs. Composite: Leaf objects perform actual work and have no children. Composite objects store child components and delegate work down the tree recursively.
  • Transparency vs. Safety Trade-Off: Defining child management methods (like add() and remove()) in the Component provides uniform transparency, while defining them only in the Composite class enforces compile-time type safety.
  • Recursive Delegation: Composite nodes forward requests to child nodes recursively until the entire subtree has processed the action, shielding the client from internal tree traversal details.

Key Architectural Benefits

Leveraging the Composite pattern offers significant software design advantages:

  • Simplified Client Code: Clients interact exclusively with the Component interface without needing conditional branches or instanceof checks.
  • Open/Closed Principle: Easily introduce new leaf types or composite containers into the application without breaking existing client workflows.
  • Flexible Hierarchy Modeling: Naturally represents complex hierarchical domains like UI component trees, file directories, or organization charts.

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=ffeC98OwBTc

Thursday, 10 October 2013

Composite Design Pattern - Class Diagram

Master Core Java Architecture & Design Patterns!

Subscribe to Ram N Java for clean code principles, GoF design patterns, and step-by-step software engineering tutorials!

🔔 Subscribe to Ram N Java

Structural Overview of the Composite Pattern

The Composite Design Pattern is a structural design pattern cataloged by the Gang of Four (GoF) that allows you to compose objects into tree structures to represent part-whole hierarchies.

To understand how tree-like structures achieve uniform treatment across individual and grouped elements, examining the UML Class Diagram is essential. It provides a visual blueprint of how relationships, inheritance, and recursive containment are organized cleanly.

Class Diagram Participants & Relationships

The standard UML class diagram for the Composite pattern contains several key participants:

  • Component: An abstract class or interface declaring the common interface for all objects in the composition, including default behaviors and operations (e.g., operation()).
  • Leaf: Represents leaf objects in the composition with no children. It implements behavior directly for primitive objects in the hierarchy.
  • Composite: Defines behavior for components having children. It stores child components (typically using a List<Component>) and implements child-related operations like add(Component), remove(Component), and getChild(int), while delegating core operations recursively.
  • Client: Manipulates objects in the hierarchy exclusively through the Component interface, remaining agnostic to whether it interacts with a Leaf or a Composite branch.

Key Architectural Benefits

Analyzing the class diagram highlights critical structural advantages:

  • Uniform Treatment: The client treats primitive and composite nodes identically through polymorphism, removing clutter like instanceof checks.
  • Extensibility: New Leaf or Composite subclasses can be added seamlessly without breaking existing client code or structural components.
  • Recursive Delegation: Composite classes naturally propagate operations across complex tree branches by delegating calls to child components.

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=WFDMGn5pVws

Click the below Image to Enlarge
Composite Design Pattern - Class Diagram
























See also:

  • Composite Design Pattern - Introduction
  • Composite Design Pattern - Implementation
  • Composite Design Pattern - Key Points
  • All Design Patterns Links
  • Composite Design Pattern - Introduction

    Master Core Java Architecture & Design Patterns!

    Subscribe to Ram N Java for clean code principles, GoF design patterns, and step-by-step software engineering tutorials!

    🔔 Subscribe to Ram N Java

    What is the Composite Design Pattern?

    The Composite Design Pattern is a foundational structural pattern defined by the Gang of Four (GoF). Its core intent is to compose objects into tree structures to represent part-whole hierarchies.

    In software engineering, modeling systems that contain both individual elements and composite containers (such as file systems with files and directories, or graphic systems with shapes and grouped shapes) often results in complicated conditional code. The Composite pattern solves this by enabling clients to treat individual objects and compositions of objects completely uniformly.

    Structural Overview & Core Participants

    The Composite pattern organizes tree-based hierarchies using clearly defined participants:

    • Component: Declares the common interface for all objects in the composition, specifying default operations and behavior shared by both simple and composite elements.
    • Leaf: Represents primitive, indivisible objects in the hierarchy that have no children. A leaf implements operations defined in the Component directly.
    • Composite: Represents branch or container nodes that hold child components. It implements methods for managing children (like adding or removing components) and delegates core requests recursively down the tree.
    • Client: Interacts with all nodes strictly through the Component interface, remaining agnostic to whether it is manipulating a single leaf or an entire nested tree structure.

    Key Architectural Benefits

    Using the Composite pattern provides distinct architectural and maintenance benefits:

    • Uniform Treatment: Eliminates repetitive type checking and branching logic (instanceof checks) across client code.
    • Open/Closed Principle: New leaf or composite types can be added seamlessly without breaking existing client code.
    • Recursive Delegation: Simplifies complex tree operations by propagating tasks automatically down nested hierarchies.

    Related Tutorials from Ram N Java


    Click here to watch in Youtube : https://www.youtube.com/watch?v=muIR-00DsuQ

    Click the below Image to Enlarge
    Composite Design Pattern - Introduction
    Composite Design Pattern - Introduction
    Composite Design Pattern - Introduction

    Tutorials