05
JanUnderstanding Association, Aggregation, Composition and Dependency relationship
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.
- 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.
- 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.
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;
Feature | Association | Aggregation | Composition |
Definition | A 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. |
Ownership | No 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. |
Lifespan | The 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. |
Example | A 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 Representation | Represented 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.