5 OOP Relations Example
5.1 Dependency & Association
// Course class that Professor depends on
class Course {
String name;
String code;
List<String> topics;
{required this.name, required this.code, required this.topics});
Course(
// Method that returns knowledge from the course
String getKnowledge() {
return 'Knowledge from $name: ${topics.join(', ')}';
}
}
// Student class that Professor is associated with
class Student {
String name;
int studentId;
List<String> learnedTopics = [];
{required this.name, required this.studentId});
Student(
// Method to remember what was taught
void remember(String knowledge) {
'$name is learning: $knowledge');
print(.add(knowledge);
learnedTopics}
// Method to show what student has learned
void showLearning() {
'\n$name has learned:');
print(for (var topic in learnedTopics) {
' - $topic');
print(}
}
}
// Professor class showing both association and dependency
class Professor {
String name;
String department;
// ASSOCIATION: Professor has a long-term relationship with students
// This is a "has-a" relationship - stored as a field
List<Student> students = [];
{required this.name, required this.department});
Professor(
// Method to add students (strengthens the association)
void addStudent(Student student) {
.add(student);
students'$name now teaches ${student.name}');
print(}
// DEPENDENCY: Professor uses Course temporarily in the teach method
// Course is not stored as a field, just used as a parameter
void teach(Course course) {
'\nProfessor $name is teaching ${course.name}');
print(
// Professor depends on Course's getKnowledge() method
String knowledge = course.getKnowledge();
// Teach all associated students
for (var student in students) {
.remember(knowledge);
student}
}
// Another method showing dependency on Course
void prepareLesson(Course course) {
'\nProfessor $name is preparing lesson for ${course.name}');
print('Topics to cover: ${course.topics.join(', ')}');
print(// Course is used temporarily, not stored
}
// Method that doesn't need Course (showing Professor can exist without Course)
void holdOfficeHours() {
'\nProfessor $name is holding office hours');
print('Available for ${students.length} students');
print(}
}
// Additional example showing different relationship types
class University {
String name;
// COMPOSITION: University owns departments (strong relationship)
List<Department> departments = [];
{required this.name});
University(
void addDepartment(String deptName) {
.add(Department(name: deptName, university: this));
departments}
}
class Department {
String name;
// Back reference
University university;
// AGGREGATION: Department has professors but doesn't own them
List<Professor> professors = [];
{required this.name, required this.university});
Department(}
// Example usage demonstrating the relationships
void main() {
// Create professor
var profSmith = Professor(
: 'Dr. Smith',
name: 'Computer Science'
department
);
// Create students and establish ASSOCIATION
var alice = Student(name: 'Alice', studentId: 12345);
var bob = Student(name: 'Bob', studentId: 12346);
.addStudent(alice);
profSmith.addStudent(bob);
profSmith
// Create courses (these will be used as DEPENDENCIES)
var oop = Course(
: 'Object-Oriented Programming',
name: 'CS101',
code: ['Classes', 'Inheritance', 'Polymorphism']
topics
);
var patterns = Course(
: 'Design Patterns',
name: 'CS301',
code: ['Singleton', 'Factory', 'Observer']
topics
);
// Professor teaches courses (DEPENDENCY in action)
.teach(oop);
profSmith.teach(patterns);
profSmith
// Professor can exist and function without courses
.holdOfficeHours();
profSmith
// Show what students learned
.showLearning();
alice.showLearning();
bob
// Demonstrate that Course objects can be created and destroyed
// without affecting Professor (loose coupling)
var tempCourse = Course(
: 'Algorithms',
name: 'CS201',
code: ['Sorting', 'Searching']
topics
);.prepareLesson(tempCourse);
profSmith// tempCourse can now go out of scope - Professor doesn't hold onto it
}
// UML Representation in comments:
/*
Professor -------> Student (Association: solid line with arrow)
| Professor "has" Students as a field
|
┆ - - - - - -> Course (Dependency: dashed line with arrow)
Professor "uses" Course in methods
Key Differences:
1. Association (Professor -> Student):
- Long-term relationship
- Student is stored as a field in Professor
- Professor "has" Students
2. Dependency (Professor --> Course):
- Temporary relationship
- Course is only used in method parameters
- Professor "uses" Course but doesn't store it
- Changes to Course interface affect Professor's methods
*/
I’ll create a comprehensive example in Dart that demonstrates the difference between dependency and association relationships.Let me explain the key differences between Dependency and Association with this example:
5.1.1 Association (Professor → Student)
Definition: A “has-a” relationship where one class has a long-term connection to another class.
Characteristics: - Student is stored as a field in Professor class - The relationship persists throughout the Professor object’s lifetime - Professor “owns” references to Students - Stronger coupling than dependency
In the code:
// Students are stored as class members field Student student
5.1.2 Dependency (Professor ⟶ Course)
Definition: A “uses-a” relationship where one class temporarily uses another class.
Characteristics: - Course is NOT stored as a field - Only used as method parameters or local variables - Temporary relationship during method execution - Weaker coupling - Professor can exist without Course
In the code:
// Course is only a parameter, not stored method teach(Course c)
5.2 Visual Representation:
Professor ————————> Student (Association: solid line)
| "Professor HAS Students"
|
┆ - - - - -> Course (Dependency: dashed line)
"Professor USES Course"
5.3 Why This Matters:
- Coupling Strength:
- Association creates stronger coupling
- Dependency creates looser coupling
- Lifetime Management:
- Associated objects (Students) live with the Professor
- Dependent objects (Courses) are temporary
- Design Flexibility:
- Dependencies are easier to change/mock/test
- Associations require more careful design
- Memory Impact:
- Associations hold references (memory implications)
- Dependencies release references after use
This pattern is fundamental in software design as it helps manage complexity and create more maintainable, testable code.