4 OOP Relation
4.1 Summary of UML Relationships (Weakest to Strongest)

4.1.1 Dependency (Weakest) A - - -> B
// 1. DEPENDENCY (Weakest) - A uses B temporarily
// Notation: A - - - -> B (dashed arrow)
class PaymentProcessor { // Class A
// No stored reference to EmailService
void processPayment(double amount, EmailService emailer) { // Class B as parameter
'Processing payment of \$$amount');
print(// Temporary use of EmailService
.sendConfirmation('Payment processed');
emailer// EmailService reference is gone after method ends
}
}
- What: A uses B temporarily
- How: B appears in method parameters, return types, or local variables
- Coupling: Very loose - A doesn’t store B
- Example: PaymentProcessor uses EmailService only during payment processing
4.1.2 Association A ——> B
// 2. ASSOCIATION - A has long-term reference to B
// Notation: A ——> B (solid arrow)
class Doctor { // Class A
String name;
List<Patient> patients = []; // Stores references to B
{required this.name});
Doctor(
void addPatient(Patient patient) {
.add(patient);
patients.doctors.add(this); // Bidirectional
patient}
}
class Patient { // Class B
String name;
List<Doctor> doctors = []; // Can have multiple doctors
{required this.name});
Patient(}
- What: A has a long-term reference to B
- How: B is stored as a field in A
- Coupling: Moderate - both can exist independently
- Example: Doctor has Patients (and Patients know their Doctors)
4.1.3 Aggregation A ◇——> B
// 3. AGGREGATION - A has B, but B can exist independently
// Notation: A ◇——> B (hollow diamond)
class Department { // Class A
String name;
List<Employee> employees = []; // Has employees but doesn't own them
{required this.name});
Department(
void addEmployee(Employee emp) {
.add(emp);
employees}
void removeEmployee(Employee emp) {
.remove(emp);
employees// Employee continues to exist
}
}
class Employee { // Class B
String name;
String id;
{required this.name, required this.id});
Employee(// Can exist without department
}
- What: A “has” B (whole-part relationship)
- How: A contains B but doesn’t control B’s lifecycle
- Coupling: Moderate - B can exist without A
- Example: Department has Employees (but Employees can change departments)
4.1.4 Composition (Strongest “has-a”) A ◆——> B
// 4. COMPOSITION (Strongest "has-a") - A owns B, B cannot exist without A
// Notation: A ◆——> B (filled diamond)
class House { // Class A
String address;
List<Room> rooms = []; // Owns rooms completely
{required this.address, required int numberOfRooms}) {
House(// Rooms are created by House
for (int i = 0; i < numberOfRooms; i++) {
.add(Room(houseAddress: address, roomNumber: i + 1));
rooms}
}
void demolish() {
'House demolished - all rooms destroyed');
print(.clear(); // Rooms cease to exist
rooms}
}
class Room { // Class B
final String houseAddress; // Cannot change house
final int roomNumber;
{required this.houseAddress, required this.roomNumber});
Room(// Cannot exist without House
}
- What: A owns B completely
- How: A creates and destroys B
- Coupling: Strong - B cannot exist without A
- Example: House has Rooms (rooms don’t exist without the house)
4.1.5 5. Implementation A - - -▷ B
// 5. IMPLEMENTATION - A implements interface B
// Notation: A - - - ▷ B (dashed arrow with hollow triangle)
abstract class Flyable { // Interface B
void fly();
}
class Bird implements Flyable { // Class A
@override
void fly() {
'Bird is flying with wings');
print(}
}
class Airplane implements Flyable { // Another A
@override
void fly() {
'Airplane is flying with engines');
print(}
}
- What: A implements interface B
- How: A must provide all methods declared in B
- Coupling: Moderate - contract-based relationship
- Example: Bird implements Flyable interface
4.1.6 6. Inheritance (Strongest) A ——▷ B
// 6. INHERITANCE (Strongest) - A is-a B
// Notation: A ——▷ B (solid arrow with hollow triangle)
class Animal { // Class B (superclass)
String species;
{required this.species});
Animal(
void breathe() {
'$species is breathing');
print(}
}
class Dog extends Animal { // Class A (subclass)
String breed;
{required this.breed}) : super(species: 'Canine');
Dog(
void bark() {
'$breed dog is barking');
print(}
}
- What: A “is-a” B
- How: A inherits all properties and methods from B
- Coupling: Very strong - changes to B affect A
- Example: Dog extends Animal
4.2 Key Design Principles:
COUPLING STRENGTH EXPLANATION:
WEAKEST ←————————————————————————————————————————————————————————————→ STRONGEST
| |
Dependency → Association → Aggregation/Implementation → Composition → Inheritance
- Dependency: Loosest coupling, temporary usage
- Association: Permanent reference, but independent
- Aggregation: Whole-part relationship, parts can exist alone
- Implementation: Contract-based, moderate coupling
- Composition: Strong ownership, parts depend on whole
- Inheritance: Tightest coupling, child IS parent
- Prefer weaker relationships when possible for flexibility
- Use composition over inheritance for better modularity
- Dependencies are easier to test than associations
- Interfaces provide flexibility while maintaining contracts
- Inheritance should represent true “is-a” relationships
The diagram shows these relationships nested to indicate that stronger relationships often include characteristics of weaker ones (e.g., inheritance includes aspects of implementation and dependency).