Aggregation in Java

Aggregation is a concept in Java that allows one class to contain objects of another class as a member variable. It is a way to achieve a “has-a” relationship between two classes. In Java, aggregation is implemented using object references.

Here’s an example to illustrate aggregation:

public class Address {
    private String street;
    private String city;
    private String state;
    private String zip;

    // constructor and getters/setters omitted for brevity

public class Person {
    private String name;
    private int age;
    private Address address; // Aggregation

    // constructor and getters/setters omitted for brevity

In this example, the Person class has an instance variable of type Address. This is an example of aggregation because a Person “has-a” Address.

We can create a Person object and set its Address using the following code:

Address address = new Address("123 Main St", "Anytown", "CA", "12345");
Person person = new Person("John Doe", 30, address);

Here, we create an Address object and pass it to the Person constructor to set the Person‘s Address.

We can also access the Person‘s Address using the getter method:

Address personAddress = person.getAddress();

Aggregation is useful for creating more complex objects that are composed of simpler objects. It allows us to create modular, reusable code by separating concerns into different classes.

Simple Example of Aggregation:

Here is a simple example of aggregation in Java:

public class Book {
    private String title;
    private String author;
    private int year;
    private Publisher publisher; // Aggregation

    public Book(String title, String author, int year, Publisher publisher) {
        this.title = title; = author;
        this.year = year;
        this.publisher = publisher;

    // Getters and setters omitted for brevity

public class Publisher {
    private String name;
    private String address;

    public Publisher(String name, String address) { = name;
        this.address = address;

    // Getters and setters omitted for brevity

In this example, the Book class has a reference to an instance of the Publisher class. The Publisher class is the simpler object that is being aggregated by the Book class.

We can create a Book object and set its Publisher using the following code:

Publisher publisher = new Publisher("Penguin Random House", "123 Main St, New York");
Book book = new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925, publisher);

Here, we create a Publisher object and pass it to the Book constructor to set the Book‘s Publisher.

We can also access the Book‘s Publisher using the getter method:

Publisher bookPublisher = book.getPublisher();

Aggregation allows us to model more complex relationships between objects. In this example, we can see that a Book “has-a” Publisher. By using aggregation, we can create more modular and reusable code that separates concerns into different classes.

When use Aggregation?

Aggregation is typically used when one class needs to reference another class as a member variable, but the two classes have a “has-a” relationship rather than an “is-a” relationship.

Here are some scenarios where aggregation can be used:

  1. Composition of complex objects: Aggregation can be used to compose complex objects by breaking them down into simpler objects. For example, a Car object may have a Engine object, Wheel objects, and other components that can be modeled as separate objects.
  2. Separation of concerns: Aggregation allows us to separate concerns into different classes, which can make our code more modular and reusable. For example, a Person object may have an Address object, which can be reused in other parts of the code.
  3. Managing dependencies: Aggregation can be used to manage dependencies between objects. For example, if a Database object needs to use a Connection object, we can use aggregation to ensure that the Connection object is created and managed separately from the Database object.
  4. Flexibility: Aggregation can make our code more flexible by allowing us to change the behavior of our program without changing the underlying structure of our classes. For example, we can change the Publisher object of a Book object without changing the Book class itself.

In general, aggregation is useful when we need to create more complex objects by combining simpler objects, manage dependencies between objects, or separate concerns into different classes. It allows us to create more modular, reusable, and flexible code.

Understanding meaningful example of Aggregation:

Let’s consider an example of an online shopping system, where a customer can place an order for one or more products. Here, we can use aggregation to represent the relationship between an order and its line items.

public class Product {
    private String name;
    private double price;

    public Product(String name, double price) { = name;
        this.price = price;

    // Getters and setters omitted for brevity

public class OrderItem {
    private Product product;
    private int quantity;

    public OrderItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;

    // Getters and setters omitted for brevity

public class Order {
    private List<OrderItem> items;
    private double total;

    public Order(List<OrderItem> items) {
        this.items = items; = calculateTotal();

    private double calculateTotal() {
        double total = 0.0;
        for (OrderItem item : items) {
            total += item.getProduct().getPrice() * item.getQuantity();
        return total;

    // Getters and setters omitted for brevity

In this example, the Product class represents a product available for purchase, the OrderItem class represents a product that has been added to an order along with its quantity, and the Order class represents an order that contains one or more OrderItems.

The Order class aggregates a list of OrderItem objects, which allows us to represent the relationship between an order and its line items. The calculateTotal() method of the Order class calculates the total price of the order by summing up the prices of each item in the order.

We can create an order with multiple items using the following code:

Product product1 = new Product("iPhone", 999.0);
Product product2 = new Product("MacBook Pro", 1999.0);

List<OrderItem> items = new ArrayList<>();
items.add(new OrderItem(product1, 2));
items.add(new OrderItem(product2, 1));

Order order = new Order(items);

In this example, we create two Product objects and add them to an order with quantities of 2 and 1, respectively. The Order object is then created by passing the list of OrderItem objects to its constructor.

By using aggregation, we can create a flexible and modular design that allows us to add or remove products from orders without changing the structure of our classes. We can also reuse the Product and OrderItem classes in other parts of our code, which makes our code more modular and easier to maintain.