5  OOP Relations Example

5.1 Dependency & Association

// Course class that Professor depends on
class Course {
  String name;
  String code;
  List<String> topics;
  
  Course({required this.name, required this.code, required this.topics});
  
  // 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 = [];
  
  Student({required this.name, required this.studentId});
  
  // Method to remember what was taught
  void remember(String knowledge) {
    print('$name is learning: $knowledge');
    learnedTopics.add(knowledge);
  }
  
  // Method to show what student has learned
  void showLearning() {
    print('\n$name has learned:');
    for (var topic in learnedTopics) {
      print('  - $topic');
    }
  }
}

// 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 = [];
  
  Professor({required this.name, required this.department});
  
  // Method to add students (strengthens the association)
  void addStudent(Student student) {
    students.add(student);
    print('$name now teaches ${student.name}');
  }
  
  // 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) {
    print('\nProfessor $name is teaching ${course.name}');
    
    // Professor depends on Course's getKnowledge() method
    String knowledge = course.getKnowledge();
    
    // Teach all associated students
    for (var student in students) {
      student.remember(knowledge);
    }
  }
  
  // Another method showing dependency on Course
  void prepareLesson(Course course) {
    print('\nProfessor $name is preparing lesson for ${course.name}');
    print('Topics to cover: ${course.topics.join(', ')}');
    // Course is used temporarily, not stored
  }
  
  // Method that doesn't need Course (showing Professor can exist without Course)
  void holdOfficeHours() {
    print('\nProfessor $name is holding office hours');
    print('Available for ${students.length} students');
  }
}

// Additional example showing different relationship types
class University {
  String name;
  
  // COMPOSITION: University owns departments (strong relationship)
  List<Department> departments = [];
  
  University({required this.name});
  
  void addDepartment(String deptName) {
    departments.add(Department(name: deptName, university: this));
  }
}

class Department {
  String name;
  University university; // Back reference
  
  // AGGREGATION: Department has professors but doesn't own them
  List<Professor> professors = [];
  
  Department({required this.name, required this.university});
}

// Example usage demonstrating the relationships
void main() {
  // Create professor
  var profSmith = Professor(
    name: 'Dr. Smith',
    department: 'Computer Science'
  );
  
  // Create students and establish ASSOCIATION
  var alice = Student(name: 'Alice', studentId: 12345);
  var bob = Student(name: 'Bob', studentId: 12346);
  
  profSmith.addStudent(alice);
  profSmith.addStudent(bob);
  
  // Create courses (these will be used as DEPENDENCIES)
  var oop = Course(
    name: 'Object-Oriented Programming',
    code: 'CS101',
    topics: ['Classes', 'Inheritance', 'Polymorphism']
  );
  
  var patterns = Course(
    name: 'Design Patterns',
    code: 'CS301',
    topics: ['Singleton', 'Factory', 'Observer']
  );
  
  // Professor teaches courses (DEPENDENCY in action)
  profSmith.teach(oop);
  profSmith.teach(patterns);
  
  // Professor can exist and function without courses
  profSmith.holdOfficeHours();
  
  // Show what students learned
  alice.showLearning();
  bob.showLearning();
  
  // Demonstrate that Course objects can be created and destroyed
  // without affecting Professor (loose coupling)
  var tempCourse = Course(
    name: 'Algorithms',
    code: 'CS201',
    topics: ['Sorting', 'Searching']
  );
  profSmith.prepareLesson(tempCourse);
  // 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:

field Student student  // Students are stored as class members

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:

method teach(Course c)  // Course is only a parameter, not stored

5.2 Visual Representation:

Professor ————————> Student    (Association: solid line)
   |                          "Professor HAS Students"
   |
   ┆ - - - - -> Course       (Dependency: dashed line)
                             "Professor USES Course"

5.3 Why This Matters:

  1. Coupling Strength:
    • Association creates stronger coupling
    • Dependency creates looser coupling
  2. Lifetime Management:
    • Associated objects (Students) live with the Professor
    • Dependent objects (Courses) are temporary
  3. Design Flexibility:
    • Dependencies are easier to change/mock/test
    • Associations require more careful design
  4. 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.