KapreSoft
From Coding to Cooking to Coins:
Antonio Lagnada's Blog on Software, Music, Food, and Finance

Design Patterns • Composition vs Aggregation

Post Date: 17 Nov 2023
 
 

Overview

When it comes to software engineering and design, understanding the concepts of composition and aggregation is crucial for creating robust and efficient domain models. These terms, often used in object-oriented programming, represent relationship patterns between objects that dictate how they interact and depend on each other. By dissecting these concepts and illustrating them with real-life examples, we can gain a deeper comprehension of their applications and significance in domain modeling.

Composition and aggregation are both associative relationships but differ in terms of ownership and life cycle of the involved objects. While both play pivotal roles in domain modeling, understanding their distinct characteristics is essential for their appropriate application in various scenarios. This article aims to demystify these concepts, providing clarity with practical examples.

Composition Domain Modeling

In domain modeling, composition and aggregation represent different types of relationships between objects. Composition implies a strong ownership, where the life cycle of the contained object is strictly bound to the container. When the container object is destroyed, so are its contents. This reflects a “part-of” relationship where the parts cannot exist independently of the whole.

Composition of an Engine and Wheel

In the figure below is an example class diagram to illustrate the concept of Composition in a UML class diagram. In this example, we’ll use a simple scenario of a Car and its integral parts, like Engine and Wheel. In Composition, these parts are entirely dependent on the Car for their existence.

Figure 1. Composition Class Diagram of an Engine and Wheel Relationship

The UML class diagram showing the composition relationship between a Car and its components, Engine and Wheels, underlining the concept that the existence of the components is dependent on the existence of the car.

Class Diagram: Composition of Engine and Wheel

Also available in: SVG | PlantText

In this diagram:

Composition of a Shopping Cart System

For a real-world service-oriented example of Composition, let’s consider an Online Shopping System. In this system, a ShoppingCart service is composed of Item services. The lifecycle of Item services is tightly coupled with the ShoppingCart - when the cart is cleared or deleted, the items within it cease to exist in that context.

Figure 2. Shopping Cart System Relationship Class Diagram

This UML diagram effectively illustrates the composition relationship in a service-oriented architecture, where the ShoppingCart service is composed of and manages the lifecycle of Item services. This setup highlights the dependency of Item services on their encompassing ShoppingCart service.

Shopping Cart System Relationship Class Diagram

Also available in: SVG | PlantText

In this diagram:

The example Java implementation below captures the essence of a composition relationship where the items are part of the shopping cart and are managed by it.

import lombok.Data;
import lombok.NoArgsConstructor;

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

@NoArgsConstructor
@Data
public class ShoppingCart {
    private List<Item> items = new ArrayList<>();

    public void addItem(Item item) {
        items.add(item);
    }

    public void removeItem(Item item) {
        items.remove(item);
    }

    public void clearCart() {
        items.clear();
    }
}

@Data
@NoArgsConstructor
public class Item {
    private String name;
    private double price;
    private int quantity;

    public Item(String name, double price, int quantity) {
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }
}

In this code:

Aggregation in Domain Modeling

Aggregation, on the other hand, suggests a weaker relationship. It indicates a “has-a” relationship, where the container object holds references to other objects but does not strictly manage their life cycles. In aggregation, the contained objects can exist independently of the container.

Aggregation of Universities and Students

This time, we’ll consider a scenario involving a University and Student to depict the aggregation relationship. In Aggregation, the Student can exist independently of the University, unlike in Composition.

Figure 3. Aggregation Class Diagram for a University Student Relationship

This UML diagram illustrates the aggregation relationship between a University and Student, demonstrating that while the university contains students, these students have an existence independent of the university.

Aggregation Class Diagram for a University Student Relationship

Also available in: SVG | PlantText

In this diagram:

Aggregation of a Library Management System

For a real-world service-oriented example of Aggregation, let’s consider a Library Management System. In this system, a Library service aggregates Book services. While the Library manages and coordinates access to Book services, each Book service can exist independently, serving its information or getting loaned out to users. The Library does not own the Book services but merely coordinates them.

Figure 4. Aggregation Class Diagram for a Library Management System

This UML diagram efficiently illustrates the aggregation relationship in a service-oriented architecture, where the Library service aggregates multiple Book services without owning them.

Aggregation Class Diagram for a Library Management System

Also available in: SVG | PlantText

In this diagram:

Following the aggregation pattern for the Library Management System with Library and Book classes, here’s how you can implement it in Java with Lombok for reducing boilerplate code.

In this code, the aggregation relationship is characterized by the Library managing a collection of Book objects without having direct control over their lifecycle. The Book objects maintain their independent existence, which is a fundamental characteristic of aggregation in object-oriented design.

import lombok.Data;
import java.util.ArrayList;
import java.util.List;

@Data
public class Library {
    private List<Book> books;

    public Library() {
        this.books = new ArrayList<>();
    }

    public void addBook(Book book) {
        books.add(book);
    }

    public void removeBook(Book book) {
        books.remove(book);
    }
}

@Data
public class Book {
    private String title;
    private String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }
}

In Conclusion

In this exploration of composition and aggregation in object-oriented programming, we’ve delved into the nuances of these two fundamental design patterns, crucial for structuring robust and efficient systems. Through real-world analogies and service-oriented examples, we’ve seen how these relationships dictate the interactions and dependencies between objects, influencing the design and functionality of software systems.

Composition, characterized by a strong, life-dependent relationship between objects, emphasizes the integral nature of components within a whole. Our example of the Online Shopping System, illustrated both in concept and Java code, demonstrates how items within a shopping cart are intrinsically linked to the cart itself, ceasing to exist independently once the cart is cleared or deleted.

On the other hand, aggregation, with its emphasis on a looser association where components can exist independently of the whole, was exemplified in the Library Management System. Here, books in a library exist as separate entities and retain their identity and existence beyond the scope of the library, a concept we observed through both conceptual explanation and Java implementation.

Both composition and aggregation offer unique advantages and are chosen based on the specific requirements and constraints of the system being designed. Understanding these patterns not only aids developers in making informed design decisions but also enhances the maintainability, scalability, and overall quality of the software.

As we continue to advance in the world of software development, the thoughtful application of such design patterns remains a cornerstone in the creation of efficient, resilient, and adaptable systems. Whether you’re a seasoned developer or a newcomer to the field, grasping the essence of composition and aggregation is a step towards mastering the art of software design and architecture.


Related Articles:

The Mock Object Design Pattern Post Date: 26 Nov 2023
The Mock Object Design Pattern is an essential aspect of modern software development, pivotal for enhancing the efficiency and reliability of software testing. It focuses on creating mock objects that simulate the behavior of real objects in a controlled environment, aimed at isolating the system under test. This isolation ensures that unit tests are independent of external elements and solely focused on the code being tested.
Understanding Deep Linking in SEO Post Date: 26 Nov 2023
In the intricate world of Search Engine Optimization (SEO), mastering the art of deep linking strategy is akin to discovering a hidden pathway to success. At its core, deep linking is not merely a set of actions but a philosophy that redefines how we perceive and structure our websites. It’s a journey into the depths of your website, unlocking the potential of each page and transforming them into powerful entities in their own right.
Agile • Best Practices and Strategies when Splitting User Stories Post Date: 25 Nov 2023
In Agile project management, User Stories play a pivotal role as fundamental building blocks. These short, simple descriptions of a software feature from the perspective of the end user are crucial in guiding teams toward creating value-driven, user-centric solutions. However, as projects evolve and complexities mount, these user stories can often become unwieldy or too broad, making them difficult to manage and execute effectively.
Agile • Why I Prefer Story Cards And Sticky Notes Post Date: 25 Nov 2023
In the dynamic realm of Agile software development, the tools and techniques we employ play a pivotal role in shaping our success. Among the many strategies that Agile practitioners use, story cards and sticky notes have proven themselves as timeless assets.
Treat Test Code As Production Code Post Date: 24 Nov 2023
In the ever-evolving landscape of software development, Java stands as a stalwart, powering a myriad of applications across diverse industries. But beneath the surface of this robust and versatile language lies a fundamental aspect often overlooked yet crucial for its success: the quality and integrity of test code.
Refactor Monolithic Code in Agile Post Date: 24 Nov 2023
In the context of software development, adaptability and scalability are the keys to staying ahead of the curve. Enter Agile development, a methodology that champions flexibility and iterative improvement. But what happens when your project inherits a monolithic codebase, where change is akin to navigating a labyrinth? It’s here that the art of refactoring comes into play.
WEBP vs PNG vs JPG Post Date: 23 Nov 2023
In the fast-paced realm of digital content, where visual appeal and speedy performance are paramount, choosing the right image format can make a world of difference. This overview sets the stage for our exploration of two formidable contenders: WebP, PNG and JPG.
Software • Code Cohesion Post Date: 23 Nov 2023
In the dynamic landscape of software development, the concept of code cohesiveness stands as a cornerstone of creating efficient and maintainable applications. Especially in Java, a language renowned for its robustness and scalability, understanding and applying cohesiveness principles can significantly elevate the quality of software projects.
ReST HATEOAS Best Practices Post Date: 09 Nov 2023
Hypertext As The Engine Of Application State (HATEOAS) is a constraint of the REST application architecture that keeps the RESTful style architecture unique. It enables the server to dynamically guide clients through the application by including hypermedia links with the responses.
HTML Anchor Tag Post Date: 09 Nov 2023
The HTML anchor tag, defined by the <a> element, is a cornerstone in web development, pivotal for creating hyperlinks. These hyperlinks are the lifelines of the internet, connecting various resources and allowing users to navigate between them seamlessly.
Advanced Strategies for Content Negotiation in RESTful APIs Post Date: 08 Nov 2023
Mastering content negotiation is essential for developing ReST APIs that excel in performance, flexibility, and user-centricity. This nuanced aspect of API design ensures that services are not only operational but are finely attuned to the diverse requirements of clients, offering a more tailored and resilient interaction.
Core Principles of ReSTful API Design - A Deep Dive Post Date: 08 Nov 2023
In the dynamic world of web development and system architecture, the design of APIs (Application Programming Interfaces) plays a crucial role in shaping the interaction between different software components. ReSTful API, standing for Representational State Transfer, has emerged as a leading standard in creating efficient, scalable, and flexible web services.
Docker Compose Best Practices Post Date: 29 Oct 2023
Docker Compose is an essential tool for developers who want to define and manage multi-container Docker applications. With its simple YAML configuration file, you can automate the deployment of your application’s services, networks, and volumes, ensuring a seamless integration and functioning of your entire system.
When to Choose Strategy Pattern Over Polymorphism Post Date: 27 Oct 2023
Navigating through the intricate landscape of software design, one often encounters the pivotal decision of whether to employ the strategy pattern or leverage polymorphism. As cornerstone concepts of object-oriented programming (OOP), each brings its unique advantages and potential pitfalls.
Leveraging Abstractions in Software Development Post Date: 27 Oct 2023
Abstractions play a crucial role in simplifying complex systems and making them more manageable, especially in the realm of software development. By understanding and implementing abstraction in software development, developers can create cleaner, more efficient, and more maintainable code.
Agile • How Code Complexity Affects Story Points Post Date: 26 Oct 2023
Software development has been revolutionized by the Agile process, which has significantly changed how projects are managed and executed. A crucial aspect of this methodology is the utilization of stories and story points, instrumental in determining the complexity and estimated time required to complete a feature or task.
Loose Coupling in Software Engineering Post Date: 25 Oct 2023
In the realm of software engineering, the concept of loose coupling represents a golden standard in design paradigms, championing a modular and flexible system that enhances software extensibility and adaptability. By embracing loose integration and prioritizing decoupled components, developers are better equipped to foster an environment conducive to growth, scalability, and long-term success.
Single Responsibility Principle in Software Development Post Date: 25 Oct 2023
The software development realm is vast, and with its expanse comes an array of techniques and methodologies that software professionals leverage to ensure the creation of robust, enterprise-grade software. At the forefront of these methodologies is the concept of object-oriented programming (OOP), a paradigm that brings a suite of design principles to the table.
The Singleton Design Pattern Post Date: 08 Jun 2023
The Singleton design pattern is a widely used and important pattern in software development. It allows the creation of a single instance of a class, ensuring that this instance is globally accessible throughout the application. In this article, we will explore various approaches to implementing Singletons in Java, examining their advantages, disadvantages, and use cases.
Is REST API Stateless? Post Date: 11 May 2023
The Representational State Transfer (REST) architectural style has become the foundation for building scalable and distributed web services. At the core of REST lies the concept of statelessness, which implies that each request sent to a RESTful API should contain all the necessary information for the server to process it, without relying on any previous interactions.
Common Misunderstandings of HTTP Status Codes Post Date: 10 May 2023
In the world of web development and API design, HTTP status codes play a crucial role in communicating the outcome of client-server interactions. However, there are several common misunderstandings surrounding these status codes that can lead to confusion and misinterpretation.
Cryptographic Algorithms: A Comparison of Security and Strength Post Date: 07 May 2023
When it comes to encryption algorithms, the question of which one is the most secure is not a straightforward one. The answer depends on a variety of factors, such as the intended use case and the context in which the algorithm is being used.
10 Best Attributes of a Software Developer Post Date: 13 Apr 2023
The sentence “What are the 10 best attributes of a software developer?” is a question that seeks to identify the key qualities that make a great software developer.