X-mas Sale: Get Upto 40% OFF on Live Training! Offer Ending in
D
H
M
S
Get Now
Understanding Association, Aggregation, Composition and Dependency relationship

Understanding Association, Aggregation, Composition and Dependency relationship

14 Oct 2024
Intermediate
136K Views
48 min read
Learn with an interactive course and practical hands-on labs

Java Programming Course

Association, Aggregation, and Composition in OOPs

Association, Aggregation, and Composition in OOPs are ways to show how classes are related. The association is a simple connection between objects without any ownership. Aggregation means one object is part of another, but it can still exist on its own. Composition is a strong relationship where one object owns another, and if the main object is deleted, the part is, too. These relationships help create clear and well-organized programs.

In this OOPs tutorial, we will learn about what is Association in OOPs, including Aggregation in OOPs, Composition in OOPs, the Difference between Association, Aggregation, and Composition, what is Dependency Relation, Examples of Association, Aggregation, Composition in, and many more.

What is Association in OOPs?

Association in OOPs refers to a relationship between two or more classes that interact with each other. It defines how objects of different classes work together but remains independent of each other. For example, in a school system, a Teacher and Student can be associated because a teacher teaches a student, but they are still separate entities. This is represented by a solid line.

Types of Association in OOPs

There are two types of Association in OOPs.

  1. Unidirectional Association: Only one of the objects in a unidirectional relationship is aware of the other. One thing can utilize or interact with another, but the second object is unaware of the first, much like a one-way street.
  2. Bidirectional Association: When two items are in bidirectional association, they may interact in both ways and are aware of one another. Both objects can communicate information and have references to one another, much like in a two-way street.

Let’s take an example of a relationship between Teacher and Student. Multiple students can associate with a single teacher, and a single student can associate with multiple teachers. However, the objects have no ownership, and both have their own lifecycle. Both can be created and deleted independently.

Types of Association in OOPs

Example

Let's understand this example in different languages such as C# Compiler, C++ Compiler, Python Compiler, and Java Compiler.

#include <iostream>
#include <string>
using namespace std;

// Forward declaration
class Teacher;

// Student class
class Student {
private:
    string name;

public:
    Student(string studentName) : name(studentName) {}

    string getName() {
        return name;
    }

    // Method showing association with Teacher
    void showTeacher(Teacher &teacher);
};

// Teacher class
class Teacher {
private:
    string name;

public:
    Teacher(string teacherName) : name(teacherName) {}

    string getName() {
        return name;
    }
};

// Student method to show associated teacher
void Student::showTeacher(Teacher &teacher) {
    cout << "Student: " << name << " is taught by Teacher: " << teacher.getName() << endl;
}

int main() {
    // Create objects of Student and Teacher
    Student student1("Rahul");
    Teacher teacher1("Mr. Sharma");

    // Show association
    student1.showTeacher(teacher1);

    return 0;
}    
using System;

// Teacher class
class Teacher {
    private string name;

    public Teacher(string teacherName) {
        name = teacherName;
    }

    public string GetName() {
        return name;
    }
}

// Student class
class Student {
    private string name;

    public Student(string studentName) {
        name = studentName;
    }

    public string GetName() {
        return name;
    }

    // Method showing association with Teacher
    public void ShowTeacher(Teacher teacher) {
        Console.WriteLine("Student: " + name + " is taught by Teacher: " + teacher.GetName());
    }
}

class Program {
    static void Main(string[] args) {
        // Create objects of Student and Teacher
        Student student1 = new Student("Rahul");
        Teacher teacher1 = new Teacher("Mr. Sharma");

        // Show association
        student1.ShowTeacher(teacher1);
    }
} 
# Main code
def main():
    # Create objects of Student and Teacher
    student1 = Student("Rahul")
    teacher1 = Teacher("Mr. Sharma")

    # Show association
    student1.show_teacher(teacher1)

# Teacher class
class Teacher:
    def __init__(self, teacher_name):
        self.name = teacher_name

    def get_name(self):
        return self.name

# Student class
class Student:
    def __init__(self, student_name):
        self.name = student_name

    def get_name(self):
        return self.name

    # Method showing association with Teacher
    def show_teacher(self, teacher):
        print(f"Student: {self.name} is taught by Teacher: {teacher.get_name()}")

# Calling the main function
if __name__ == "__main__":
    main()  
  
// Main class
public class Main {
    public static void main(String[] args) {
        // Create objects of Student and Teacher
        Student student1 = new Student("Rahul");
        Teacher teacher1 = new Teacher("Mr. Sharma");

        // Show association
        student1.showTeacher(teacher1);
    }
}

// Teacher class
class Teacher {
    private String name;

    public Teacher(String teacherName) {
        this.name = teacherName;
    }

    public String getName() {
        return name;
    }
}

// Student class
class Student {
    private String name;

    public Student(String studentName) {
        this.name = studentName;
    }

    public String getName() {
        return name;
    }

    // Method showing association with Teacher
    public void showTeacher(Teacher teacher) {
        System.out.println("Student: " + this.name + " is taught by Teacher: " + teacher.getName());
    }
}    

Output

  Student: Rahul is taught by Teacher: Mr. Sharma

Aggregation in OOPs

Aggregation in OOPs refers to a type of relationship where one class contains a reference to another class, but both can exist independently. It shows a "has-a" relationship, like how a school has teachers, but the teachers can exist without the school. This means the contained object (like the teacher) isn’t dependent on the containing object (like the school). This is represented by a hollow diamond followed by a line.

Let’s take an example of a relationship between the Department and the Teacher. A Teacher may belong to multiple departments, so the teacher is part of multiple departments. But if we delete a Department, the Teacher Object will not be destroyed.

Example

Let's understand this example in different languages such as C# Compiler, C++ Compiler, Python Compiler, and Java Compiler.

#include <iostream>
#include <string>
#include <vector>
using namespace std;

// Teacher class
class Teacher {
private:
    string name;

public:
    Teacher(string teacherName) : name(teacherName) {}

    string getName() const {
        return name;
    }
};

// Department class
class Department {
private:
    string deptName;
    vector<Teacher*> teachers; // Aggregation: Department "has" Teachers

public:
    Department(string departmentName) : deptName(departmentName) {}

    // Add teacher to the department
    void addTeacher(Teacher* teacher) {
        teachers.push_back(teacher);
    }

    // Show teachers in the department
    void showTeachers() const {
        cout << "Department: " << deptName << " has the following teachers:" << endl;
        for (const auto& teacher : teachers) {
            cout << teacher->getName() << endl;
        }
    }
};

int main() {
    // Create Teachers
    Teacher teacher1("Mr. Sharma");
    Teacher teacher2("Ms. Gupta");

    // Create Department
    Department dept("Computer Science");

    // Add teachers to the department
    dept.addTeacher(&teacher1);
    dept.addTeacher(&teacher2);

    // Show teachers in the department
    dept.showTeachers();

    return 0;
}
    
using System;
using System.Collections.Generic;

// Teacher class
class Teacher {
    private string name;

    public Teacher(string teacherName) {
        this.name = teacherName;
    }

    public string GetName() {
        return name;
    }
}

// Department class
class Department {
    private string deptName;
    private List<Teacher> teachers; // Aggregation: Department "has" Teachers

    public Department(string departmentName) {
        deptName = departmentName;
        teachers = new List<Teacher>();
    }

    // Add teacher to the department
    public void AddTeacher(Teacher teacher) {
        teachers.Add(teacher);
    }

    // Show teachers in the department
    public void ShowTeachers() {
        Console.WriteLine($"Department: {deptName} has the following teachers:");
        foreach (var teacher in teachers) {
            Console.WriteLine(teacher.GetName());
        }
    }
}

class Program {
    static void Main(string[] args) {
        // Create Teachers
        Teacher teacher1 = new Teacher("Mr. Sharma");
        Teacher teacher2 = new Teacher("Ms. Gupta");

        // Create Department
        Department dept = new Department("Computer Science");

        // Add teachers to the department
        dept.AddTeacher(teacher1);
        dept.AddTeacher(teacher2);

        // Show teachers in the department
        dept.ShowTeachers();
    }
}
# Main code
def main():
    # Create Teachers
    teacher1 = Teacher("Mr. Sharma")
    teacher2 = Teacher("Ms. Gupta")

    # Create Department
    dept = Department("Computer Science")

    # Add teachers to the department
    dept.add_teacher(teacher1)
    dept.add_teacher(teacher2)

    # Show teachers in the department
    dept.show_teachers()

# Teacher class
class Teacher:
    def __init__(self, teacher_name):
        self.name = teacher_name

    def get_name(self):
        return self.name

# Department class
class Department:
    def __init__(self, department_name):
        self.dept_name = department_name
        self.teachers = []  # Aggregation: Department "has" Teachers

    # Add teacher to the department
    def add_teacher(self, teacher):
        self.teachers.append(teacher)

    # Show teachers in the department
    def show_teachers(self):
        print(f"Department: {self.dept_name} has the following teachers:")
        for teacher in self.teachers:
            print(teacher.get_name())

# Calling the main function
if __name__ == "__main__":
    main()
    
import java.util.ArrayList;
import java.util.List;

// Main class
public class Main {
    public static void main(String[] args) {
        // Create Teachers
        Teacher teacher1 = new Teacher("Mr. Sharma");
        Teacher teacher2 = new Teacher("Ms. Gupta");

        // Create Department
        Department dept = new Department("Computer Science");

        // Add teachers to the department
        dept.addTeacher(teacher1);
        dept.addTeacher(teacher2);

        // Show teachers in the department
        dept.showTeachers();
    }
}

// Teacher class
class Teacher {
    private String name;

    public Teacher(String teacherName) {
        this.name = teacherName;
    }

    public String getName() {
        return name;
    }
}

// Department class
class Department {
    private String deptName;
    private List<Teacher> teachers; // Aggregation: Department "has" Teachers

    public Department(String departmentName) {
        this.deptName = departmentName;
        this.teachers = new ArrayList<>();
    }

    // Add teacher to the department
    public void addTeacher(Teacher teacher) {
        teachers.add(teacher);
    }

    // Show teachers in the department
    public void showTeachers() {
        System.out.println("Department: " + deptName + " has the following teachers:");
        for (Teacher teacher : teachers) {
            System.out.println(teacher.getName());
        }
    }
}
    

Output

Department: Computer Science has the following teachers:
Mr. Sharma
Ms. Gupta

Composition in OOPs

Composition in OOPs is a way to build a class using objects of other classes, showing a "has-a" relationship. For example, a house has rooms, so the House class would contain objects of the Room class. This allows for the creation of complex objects by combining simpler ones, making the design more modular and flexible.

Let’s take an example of a relationship between House and rooms. A house can contain multiple rooms. There is no independent life of the room, and any room cannot belong to two different houses. If we delete the house, the room will automatically be deleted.

Example

Let's understand this example using different compilers, such as C# Compiler, C++ Compiler, Python Compiler, and Java Compiler.

#include <iostream>
#include <vector>
#include <string>

class Room {
public:
    std::string name;

    // Constructor to initialize the room name
    Room(const std::string& roomName) : name(roomName) {}

    // Function to display room name
    void display() const {
        std::cout << "Room: " << name << std::endl;
    }
};

class House {
private:
    std::vector<Room> rooms; // House has multiple rooms

public:
    // Function to add a room to the house
    void addRoom(const Room& room) {
        rooms.push_back(room); // Adding a room to the house
    }

    // Function to show all rooms in the house
    void showRooms() const {
        std::cout << "The house has the following rooms:" << std::endl;
        for (const auto& room : rooms) {
            room.display(); // Displaying each room
        }
    }
};

int main() {
    House myHouse; // Create a House object

    // Create Room objects
    Room livingRoom("Living Room");
    Room kitchen("Kitchen");
    Room bedroom("Bedroom");

    // Add rooms to the house
    myHouse.addRoom(livingRoom);
    myHouse.addRoom(kitchen);
    myHouse.addRoom(bedroom);

    // Show the rooms in the house
    myHouse.showRooms();

    return 0;
}
using System;
using System.Collections.Generic;

class Room
{
    public string Name { get; private set; }

    // Constructor to initialize the room name
    public Room(string roomName)
    {
        Name = roomName;
    }

    // Function to display room name
    public void Display()
    {
        Console.WriteLine("Room: " + Name);
    }
}

class House
{
    private List<Room> rooms = new List<Room>(); // House has multiple rooms

    // Function to add a room to the house
    public void AddRoom(Room room)
    {
        rooms.Add(room); // Adding a room to the house
    }

    // Function to show all rooms in the house
    public void ShowRooms()
    {
        Console.WriteLine("The house has the following rooms:");
        foreach (var room in rooms)
        {
            room.Display(); // Displaying each room
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        House myHouse = new House(); // Create a House object

        // Create Room objects
        Room livingRoom = new Room("Living Room");
        Room kitchen = new Room("Kitchen");
        Room bedroom = new Room("Bedroom");

        // Add rooms to the house
        myHouse.AddRoom(livingRoom);
        myHouse.AddRoom(kitchen);
        myHouse.AddRoom(bedroom);

        // Show the rooms in the house
        myHouse.ShowRooms();
    }
}
def main():
    # Create a House object
    my_house = House()

    # Create Room objects
    living_room = Room("Living Room")
    kitchen = Room("Kitchen")
    bedroom = Room("Bedroom")

    # Add rooms to the house
    my_house.add_room(living_room)
    my_house.add_room(kitchen)
    my_house.add_room(bedroom)

    # Show the rooms in the house
    my_house.show_rooms()

class Room:
    # Constructor to initialize the room name
    def __init__(self, room_name):
        self.name = room_name

    # Method to display room name
    def display(self):
        print(f"Room: {self.name}")

class House:
    # Constructor to initialize list of rooms
    def __init__(self):
        self.rooms = []  # House has multiple rooms

    # Method to add a room to the house
    def add_room(self, room):
        self.rooms.append(room)  # Adding a room to the house

    # Method to show all rooms in the house
    def show_rooms(self):
        print("The house has the following rooms:")
        for room in self.rooms:
            room.display()  # Displaying each room

if __name__ == "__main__":
    main()
    
import java.util.ArrayList;
import java.util.List;

class Room {
    private String name;

    // Constructor to initialize the room name
    public Room(String roomName) {
        this.name = roomName;
    }

    // Method to display room name
    public void display() {
        System.out.println("Room: " + name);
    }
}

class House {
    private List<Room> rooms = new ArrayList<>(); // House has multiple rooms

    // Method to add a room to the house
    public void addRoom(Room room) {
        rooms.add(room); // Adding a room to the house
    }

    // Method to show all rooms in the house
    public void showRooms() {
        System.out.println("The house has the following rooms:");
        for (Room room : rooms) {
            room.display(); // Displaying each room
        }
    }
}

public class Main {
    public static void main(String[] args) {
        House myHouse = new House(); // Create a House object

        // Create Room objects
        Room livingRoom = new Room("Living Room");
        Room kitchen = new Room("Kitchen");
        Room bedroom = new Room("Bedroom");

        // Add rooms to the house
        myHouse.addRoom(livingRoom);
        myHouse.addRoom(kitchen);
        myHouse.addRoom(bedroom);

        // Show the rooms in the house
        myHouse.showRooms();
    }
}
    

Output

The house has the following rooms:
Room: Living Room
Room: Kitchen
Room: Bedroom 

Dependency In OOPs

Dependency in OOPs means that one class needs help from another class to work properly, showing a "uses-a" relationship. For example, a car needs fuel to run, so the car class uses a fuel class temporarily. It's like borrowing something from another class to complete a task. This is represented by a dashed arrow.

Let’s take an example of a relationship between client and service. A client is dependent on the service for implementing its functionalities.

Example

Let's understand this example in different languages such as C# Compiler, C++ Compiler, Python Compiler, and Java Compiler.

#include <iostream>
#include <string>

class Service {
public:
    // Method that performs car service
    std::string performService() {
        return "Car service completed!";
    }
};

class Car {
private:
    std::string model;

public:
    // Constructor to initialize the car's model
    Car(const std::string& carModel) : model(carModel) {}

    // Method that depends on the Service class
    void serviceCar(Service& service) {
        std::cout << "The " << model << " car is being serviced." << std::endl;
        std::cout << service.performService() << std::endl;
    }
};

int main() {
    // Create a Service object
    Service carService;

    // Create a Car object
    Car myCar("Toyota");

    // Car uses the Service object to perform the service
    myCar.serviceCar(carService);

    return 0;
}
    
using System;

class Service
{
    // Method that performs car service
    public string PerformService()
    {
        return "Car service completed!";
    }
}

class Car
{
    private string model;

    // Constructor to initialize the car's model
    public Car(string carModel)
    {
        model = carModel;
    }

    // Method that depends on the Service class
    public void ServiceCar(Service service)
    {
        Console.WriteLine($"The {model} car is being serviced.");
        Console.WriteLine(service.PerformService());
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create a Service object
        Service carService = new Service();

        // Create a Car object
        Car myCar = new Car("Toyota");

        // Car uses the Service object to perform the service
        myCar.ServiceCar(carService);
    }
}
class Service:
    # Method that performs car service
    def perform_service(self):
        return "Car service completed!"

class Car:
    def __init__(self, car_model):
        self.model = car_model  # Initialize the car's model

    # Method that depends on the Service class
    def service_car(self, service):
        print(f"The {self.model} car is being serviced.")
        print(service.perform_service())

def main():
    # Create a Service object
    car_service = Service()

    # Create a Car object
    my_car = Car("Toyota")

    # Car uses the Service object to perform the service
    my_car.service_car(car_service)

if __name__ == "__main__":
    main()
    
class Service {
    // Method that performs car service
    public String performService() {
        return "Car service completed!";
    }
}

class Car {
    private String model;

    // Constructor to initialize the car's model
    public Car(String carModel) {
        this.model = carModel;
    }

    // Method that depends on the Service class
    public void serviceCar(Service service) {
        System.out.println("The " + model + " car is being serviced.");
        System.out.println(service.performService());
    }
}

public class Main {
    public static void main(String[] args) {
        // Create a Service object
        Service carService = new Service();

        // Create a Car object
        Car myCar = new Car("Toyota");

        // Car uses the Service object to perform the service
        myCar.serviceCar(carService);
    }
}
    

Output

The Toyota car is being serviced.
Car service completed!

Difference Among Association, Aggregation, and Composition

Here are the key differences between Association, Aggregation, and Composition;

Difference Among Association, Aggregation, and Composition

FeatureAssociationAggregationComposition
DefinitionA relationship where one class uses or interacts with another class.A particular type of association where one class is a part of another class, but both can exist independently.A strong relationship is one in which one class is a part of another, and the part cannot exist independently of the whole.
OwnershipNo ownership: both classes can exist independently.Partial ownership: the whole can exist independently of its parts.Full ownership: the whole cannot exist without its parts.
LifespanThe lifespan of the associated objects is independent.The lifespan of the whole and its parts can differ.The lifespan of the parts is tied to the lifespan of the whole.
ExampleA teacher and a student (a teacher teaches students, but they exist independently).A classroom and a school (a classroom belongs to a school, but it can exist without it).A house and its rooms (rooms cannot exist without the house).
UML RepresentationRepresented by a solid line between classes.Represented by a solid line with an empty diamond at the whole end.Represented by a solid line with a filled diamond at the whole end.
Read More: Top 50 OOPs Interview Questions and Answers
Conclusion

In conclusion, understanding association, aggregation, and composition is essential in programming. Association shows how classes connect, aggregation indicates a part-whole relationship where parts can exist independently, and composition means parts cannot exist without the whole. Knowing these concepts helps create better and more organized code. This makes it easier to build and maintain applications effectively. For mastering Java and C# language, ScholarHat provides Full-Stack .NET Developer Certification Training Course and Full-Stack Java Developer Certification Training Course.

FAQs

Yes, association can exist without implying either aggregation or composition. For instance, a Teacher might be associated with a Course, but the Teacher does not own or depend on the lifecycle of the Course

The association can represent various types of relationships, including "has-a," but not always. Association is a general term for any kind of connection between classes, while "has-a" is more specific to aggregation or composition. 

 The main difference is the dependency of lifecycles. In Aggregation, the parts (objects) can live independently of the whole. In Composition, the parts cannot live independently; when the whole object is destroyed, its parts are also destroyed. 
Share Article
About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at ScholarHat)

Shailendra Chauhan, Founder and CEO of ScholarHat by DotNetTricks, is a renowned expert in System Design, Software Architecture, Azure Cloud, .NET, Angular, React, Node.js, Microservices, DevOps, and Cross-Platform Mobile App Development. His skill set extends into emerging fields like Data Science, Python, Azure AI/ML, and Generative AI, making him a well-rounded expert who bridges traditional development frameworks with cutting-edge advancements. Recognized as a Microsoft Most Valuable Professional (MVP) for an impressive 9 consecutive years (2016–2024), he has consistently demonstrated excellence in delivering impactful solutions and inspiring learners.

Shailendra’s unique, hands-on training programs and bestselling books have empowered thousands of professionals to excel in their careers and crack tough interviews. A visionary leader, he continues to revolutionize technology education with his innovative approach.
Accept cookies & close this