Understanding Relationships Between Objects
In object-oriented programming (OOP), relationships between objects are fundamental to designing flexible and maintainable systems.
These relationships define how objects interact, collaborate, and depend on each other to solve complex problems.
Key Relationships in OOP
- Dependency ("uses")
- Aggregation ("has-a")
- Inheritance ("is-a")
Imagine a traffic simulation model:
- Vehicle: Have subclasses CityCar and LargeTruck (inheritance).
- TrafficLight: Uses a Timer to control signals (dependency).
- Road: Has multiple Vehicle objects (aggregation).
Let's explore each of these relationships in detail.
Dependency ("Uses-a") Relationship
- A dependency relationship occurs when one object relies on another to function.
- This is often described as a "uses" relationship.
Dependency can be:
- Temporary: The relationship exists only when a specific action is performed.
- Unidirectional: One object depends on another, but not necessarily vice versa.
class Printer {
public void print(String message) {
System.out.println(message);
}
}
class Report {
public void generate() {
Printer printer = new Printer(); // used temporarily
printer.print("Report generated");
}
}Here, Report depends on Printer to print
In UML diagrams, dependency is represented by a dashed arrow pointing from the dependent class to the class it depends on.
Dependency is useful for allowing objects to interact without being tightly coupled.
When designing systems, aim to minimise dependencies.
Why Reduce Dependencies?
- Maintenance overheads: High dependencies mean changes in one object can ripple through the system.
- Code reusability: Strong dependencies make it hard to reuse code in different contexts.
- Flexibility: Reducing dependencies allows for easier updates and modifications.
- Aim to design objects that are loosely coupled.
- This means they interact with each other through well-defined interfaces, minimising direct dependencies.
Imagine an address book that needs to read contact data from a local file, database, or network.
- Initial design: The AddressBook class depends on three separate objects: LocalFileReader, DatabaseReader, and NetworkReader.
- New design: Introduce an InputStreamReader object that handles all data sources.
- Result: The AddressBook now depends only on InputStreamReader, reducing maintenance overhead.
Aggregation ("Has-a") Relationship
- Aggregation is a "has-a" relationship, where one object contains or is composed of other objects.
- However, the contained objects can exist independently of the parent.
- Think of aggregation like a library and its books.
- The library has books, but the books can exist outside the library.
Characteristics of aggregation:
- Weak Coupling: The lifecycle of the contained object is independent of the parent.
- Ownership: The parent "owns" the child, but the child can exist without the parent.
Consider a Department class that has a Teacher.
class Teacher {
private String name; // attribute
Teacher(String name) { // constructor
this.name = name;
}
public String getName() { // getter
return name;
}
}
class Department {
private String deptName;
private Teacher teacher; // aggregation: Department uses Teacher
public Department(String deptName, Teacher teacher) {
this.deptName = deptName;
this.teacher = teacher;
}
public void showDetails() {
System.out.println("Department: " + deptName);
System.out.println("Teacher: " + teacher.getName());
}
public static void main(String[] args) {
Teacher t1 = new Teacher("Dr. Smith"); // teacher exists independently
Department d1 = new Department("Computer Science", t1);
d1.showDetails();
}
}
The Teacher can exist independently of the Department.
In UML diagrams, aggregation is represented by a hollow diamond connected to the parent class.
Inheritance ("Is-a") Relationship
Inheritance is an "is-a" relationship, where a subclass inherits attributes and methods from a superclass.
Characteristics of inheritance:
- Hierarchical: Establishes a parent-child relationship.
- Reusability: Allows subclasses to reuse and extend the functionality of the superclass.
Student and Professor inherit from Person, sharing common attributes and methods.
class Person { // super class
protected String name;
protected int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void introduce() {
System.out.println("Hi, I am " + name + " and I am " + age + " years old.");
}
}
class Student extends Person { // first subclass
private String major;
public Student(String name, int age, String major) {
super(name, age);
this.major = major;
}
public void study() {
System.out.println(name + " is studying " + major + ".");
}
}
class Professor extends Person { // second subclass
private String department;
public Professor(String name, int age, String department) {
super(name, age);
this.department = department;
}
public void teach() {
System.out.println(name + " is teaching in the " + department + " department.");
}
}
public class Main { // class for testing
public static void main(String[] args) {
Student s = new Student("Alice", 20, "Computer Science");
Professor p = new Professor("Dr. Smith", 45, "Mathematics");
s.introduce(); // output: Hi, I am Alice and I am 20 years old.
s.study(); // output: Alice is studying Computer Science.
p.introduce(); // output: Hi, I am Dr. Smith and I am 45 years old.
p.teach(); // Dr. Smith is teaching in the Mathematics department.
}
}
In UML diagrams, inheritance is represented by a hollow triangle pointing from the subclass to the superclass.
- Avoid overusing inheritance, as it can lead to rigid hierarchies.
- Consider composition(aggregation) as an alternative for greater flexibility.
Constructing Related Objects
An approximate step-by-step guide is:
- Identify the Core Objects: Determine the main entities in the problem.
- Define Attributes and Methods: Specify the data and actions for each object.
- Establish Relationships: Determine how objects interact with each other.
- Use UML Diagrams: Visualise the structure and relationships using UML class diagrams.
- In a vehicle management system, core objects might include Vehicle, Car, Truck, and Motorcycle.
- A Vehicle might have attributes like numberOfWheels and methods like startEngine().
- A Car inherits from Vehicle, while an Engine is a part of a Vehicle.
- Can you identify the relationships between objects in a system you recently studied or designed?
- How do these relationships impact the system's flexibility and maintainability?