Composite Design Pattern In C++ - C++ Programming Tutorial
C++ Course / Design Patterns / Composite Design Pattern In C++

Composite Design Pattern In C++

BLUF: Mastering Composite Design Pattern In C++ is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: Composite Design Pattern In C++

C++ is renowned for its efficiency. Learn how Composite Design Pattern In C++ enables low-level control and high-performance computing in the tutorial below.

The compositional design pattern in C++ serves as a structural approach that treats collections of objects and single objects in a uniform manner. These design patterns prove especially beneficial when managing hierarchies of parts and wholes, enabling clients to engage with both singular elements and intricate structures consistently. Within C++, the composite pattern enhances code adaptability, simplifying the addition of new component types, modifications to hierarchy arrangements, and execution of recursive tasks within the composite framework.

The essential elements of the composite design pattern consist of the "component," serving as the shared interface for all specific classes, whether they function as leaf nodes or composite nodes. The "leaf" denotes the terminal entities devoid of child components. On the other hand, the "composite" can encompass both leaf and additional composite entities, creating a recursive hierarchy.

When developers encounter situations where they are utilizing numerous objects similarly and duplicating code to manage each one, the composite pattern becomes advantageous. It simplifies the process by treating primitives and composites uniformly, especially when clients overlook the distinction between object compositions and individual objects.

Simple example to understand the composite design pattern:

Imagine a scenario where you need to purchase groceries from the market and you have already compiled a list of items. This list can consist of two different types: specific individual items and broader categories of items.

Categories are used to group various items together. For instance, fruits category includes apples, bananas, and oranges, while snacks category consists of chips, biscuits, and cookies.

Here, the eggs, milk, and bread are considered leaf components, serving as fundamental building blocks that do not include any other items. In contrast, categories such as fruits and snacks are considered composite components since they consist of individual items as well as other categories. For instance, apples within the fruits category exemplify this composition.

When shopping, you can interact with individual items and categories in a consistent manner. There is no need to differentiate between selecting a single item or a whole category since both actions follow the same process of purchasing items.

Main components of the Composite Design Pattern:

Component: This serves as the foundational class that outlines the shared interface for all concrete classes. It consists of abstract functions that are virtual.

A Leaf represents singular entities without children, inheriting from the component class to offer a specific realization of its interface.

Composite: It signifies a collection of elements, encompassing leaf entities as well as other composite entities. This class inherits from the component class and includes a container for holding child components. It incorporates functions for managing the children and implements all the methods of the component class.

The software application utilizes the component interface to seamlessly collaborate with both individual leaf elements and composite objects. This allows it to engage with the components without distinguishing between them as leaf nodes or composite structures.

Real life situations where Composite Design Patterns are used:

Graphic systems:

In applications for graphic design, various shapes, lines, and other graphical components can be merged to form intricate drawings. This method enables consistent handling of individual graphical components and arrangements of these components.

User interfaces:

These interfaces are organized in a hierarchical manner, containing elements such as buttons, panels, and windows. The composite design pattern ensures a consistent treatment of both individual UI components and composite components.

File systems:

The files are stored in directories in a manner resembling a tree structure. This system is beneficial for consistently representing and engaging with the hierarchical file system structure.

Document Object Model:

In the realm of web development, the Document Object Model (DOM) stands for the structure of HTML documents. This methodology is employed to portray HTML components, viewing a sophisticated document as an amalgamation of distinct elements such as paragraphs, images, and headings.

Menu Systems:

Menu systems within applications commonly follow a hierarchical arrangement, featuring menus that house sub-menus and individual menu items. The Composite Pattern enables the modeling of menu hierarchies in a manner that facilitates seamless navigation and manipulation.

CAD software:

Drawing programs and Computer-Aided Design (CAD) applications make use of the composite pattern to effectively handle intricate arrangements of shapes, lines, and various other elements involved in drawings.

Database Design:

Databases frequently store data in a hierarchical format, such as employee reporting structures, product classifications, or file systems. These structures are commonly employed for executing recursive queries, encapsulating data retrieval processes, and more.

Program to illustrate the Composite Design Pattern:

Let's explore a real-life scenario demonstrating the composite design pattern within a drawing software. In this case, we aim to depict various shapes like circles, rectangles, and triangles in a manner that enables us to handle single shapes and combined drawings consistently.

Example

#include <iostream>
#include <vector>
using namespace std;
// Component
class Shape {
public:
 virtual void draw() const = 0;
};

// Leaf
class Circle : public Shape {
public:
 void draw() const override {
 cout << "Drawing Circle\n";
 }
};

// Leaf
class Rectangle : public Shape {
public:
 void draw() const override {
 cout << "Drawing Rectangle\n";
 }
};

// Leaf
class Triangle : public Shape {
public:
 void draw() const override {
 cout << "Drawing Triangle\n";
 }
};

// Composite
class Drawing : public Shape {
private:
 vector<Shape*> shapes;

public:
 void addShape(Shape* shape) {
 shapes.push_back(shape);
 }

 void draw() const override {
 cout << "Drawing Composite Shape\n";
 for (const auto& shape : shapes) {
 shape->draw();
 }
 }
};

int main() {
 // Creating individual shapes
 Circle circle;
 Rectangle rectangle;
 Triangle triangle;

 // Creating a composite drawing
 Drawing compositeDrawing;
 compositeDrawing.addShape(&circle);
 compositeDrawing.addShape(&rectangle);

 // Adding a triangle to the composite drawing
 Drawing nestedDrawing;
 nestedDrawing.addShape(&triangle);
 compositeDrawing.addShape(&nestedDrawing);

 // Drawing individual shapes and the composite drawing
 circle.draw();
 rectangle.draw();
 triangle.draw();
 compositeDrawing.draw();

 return 0;
}

Output:

Explanation:

The software will provide a detailed explanation of the composite design pattern. Within the software, the primary element is the shape class. This class does not contain any variables but includes a single abstract function that defines the shared interface for rendering the shapes.

Following this, we have the leaf elements which consist of the Rectangle class, Circle class, and Triangle class. These specific classes do not contain any variables within them. The purpose of the draw method is to provide a concrete implementation for drawing each individual shape.

The Drawing class plays the role of the composite in the composite design pattern. It includes a vector variable that stores shapes of various types. This vector acts as a container for both leaf and composite shapes. The class provides two functions: addShape and draw. The addShape function accepts a pointer to a shape, whether it's a leaf or another composite, and adds it to the shapes vector within the Drawing object. This function has a return type of void.

On the other hand, the draw function in the Drawing class does not take any parameters and also returns void. This function overrides the draw function defined in the Shape base class. It operates by iterating through the shapes vector and invoking the draw function for each individual shape. This process effectively renders the complete composite structure on the canvas.

The control flow of the Program is as follows:

Form Distinct Geometric Forms (Circle, Square, Triangle):

Shapes are created as individual instances.

  • Generate Composite Drawing (compositeDrawing):

A composite drawing object is created.

Integrate Shapes into Composite Drawing (compositeDrawing):

The Circle and Rectangle instances are included in the compositeDrawing.

  • Establish a Nested Drawing (nestedDrawing):

Instantiate another drawing object named nestedDrawing.

Insert the Nested Drawing into the Composite Drawing named compositeDrawing:

The compositeDrawing now includes the addition of the nestedDrawing, which contains a Triangle.

  • Illustrate Single Shapes and Composite Drawing:

The draw method is called for every specific shape such as Circle, Rectangle, and Triangle.

The draw function is executed for the compositeDrawing, triggering the draw functions for each specific shape it encompasses.

The code example showcases the Composite Design Pattern, which enables the uniform treatment of shapes using a shared interface (Shape). It involves the creation of individual shapes and composite drawings, with the composite drawing containing nested elements. By invoking the draw function, both individual shapes and the composite structure are visually represented. This design pattern facilitates the smooth incorporation of leaf and composite objects, offering a cohesive approach to managing intricate object arrangements.

Advantages of Composite design pattern:

There are numerous benefits associated with the composite design pattern in C++. Some key advantages of utilizing the composite design pattern in C++ include:

Unified Interface:

The design pattern offers a consistent interface for managing both single entities and complex structures. Users can engage with entities consistently, regardless of whether they are individual elements or interconnected nodes within a composition.

Flexibility and Extensibility:

The design pattern simplifies the process of integrating additional component types into the system. Whether it's a fresh leaf or a new composite, the client code stays consistent. Incorporating new forms, items, or classifications becomes a smooth procedure, enhancing the adaptability of the system.

Code Reusability:

Elements, whether they are individual parts or combinations, have a shared interface. This encourages the reuse of code, allowing the same client code to interact with different components in the structure. Reusable code streamlines maintenance tasks and minimizes the chances of errors creeping in.

Recursive Operations:

The compound configuration facilitates iterative functions across the complete hierarchy. It proves especially beneficial for activities requiring navigation and modification of intricate object arrangements. Actions performed on a compound node are inherently extended to its offspring, streamlining the execution of algorithms that necessitate handling the whole configuration.

Hierarchical Structures:

The design is ideal for depicting and managing hierarchical arrangements, like relationships between components, consistently.

Consistent Client Code:

Users engage with the composite arrangement regularly, resulting in neater and easier-to-understand code. Avoiding the necessity of conditional statements for managing various object types is possible because the standard interface conceals the specifics of the implementation.

Encapsulation:

The composite design pattern encapsulates the intricacy of handling both individual objects and compositions within the composite nodes.

Conclusion:

The Composite Design Pattern in C++ offers an effective and adaptable approach to organizing code for hierarchies involving parts and wholes. By standardizing the interface for both individual elements and compositions, it streamlines interactions for clients and boosts code versatility. Its essential elements - Component, Leaf, Composite, and Client - collaborate seamlessly, fostering code flexibility and reusability. Various real-world systems, such as graphic systems and file systems, leverage its uniform handling of hierarchical structures. The grocery items example provided demonstrates the pattern's straightforwardness and efficiency in realistic scenarios. In summary, the Composite Pattern serves as a valuable asset for constructing scalable, sustainable, and coherent software architectures.

Input Required

This code uses input(). Please provide values below:

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience