UML Class Diagrams: Complete Guide

What is a Class Diagram? A class diagram is a type of static structure diagram used in UML to describe the structure of a system by showing the system's classes, their attributes, methods, and the relationships among the classes.


πŸ“‹ Table of Contents

  1. Access Modifiers
  2. Associations
  3. Relationships
  4. Dependency
  5. Real-World Examples
  6. Interview Questions
  7. Summary

πŸ” Access Modifiers

Access modifiers control the visibility and accessibility of class members (attributes and methods). They define which parts of your code can access specific members.

Visibility Levels

Symbol Name Visibility Use Case
+ Public Everywhere General APIs, methods callers need to use
- Private Within class only Internal implementation details
# Protected Class + Subclasses Shared implementation for inheritance
~ Package Same package only Internal package-level access

πŸ“Š ASCII Diagram: Access Modifier Visibility

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           VISIBILITY SCOPE              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                         β”‚
β”‚  + Public                               β”‚
β”‚    β”œβ”€β”€ Can be accessed from anywhere    β”‚
β”‚    β”œβ”€β”€ No restrictions                  β”‚
β”‚    └── Use for public interfaces        β”‚
β”‚                                         β”‚
β”‚  # Protected                            β”‚
β”‚    β”œβ”€β”€ Accessible in class + subclasses β”‚
β”‚    β”œβ”€β”€ Hidden from outside clients      β”‚
β”‚    └── Supports inheritance patterns    β”‚
β”‚                                         β”‚
β”‚  - Private                              β”‚
β”‚    β”œβ”€β”€ Only accessible within class     β”‚
β”‚    β”œβ”€β”€ Completely hidden from outside   β”‚
β”‚    └── Best for encapsulation           β”‚
β”‚                                         β”‚
β”‚  ~ Package                              β”‚
β”‚    β”œβ”€β”€ Only within same package         β”‚
β”‚    β”œβ”€β”€ Cross-package access blocked     β”‚
β”‚    └── Used for internal implementation β”‚
β”‚                                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example: BankAccount Class

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      BankAccount               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Attributes:                    β”‚
β”‚ + accountNumber: String ──┐    β”‚
β”‚ # balance: Double ────────┼──┐ β”‚
β”‚ - PIN: Integer ───────────┼──┼──
β”‚                           β”‚  β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚ β”‚
β”‚ Methods:                   β”‚  β”‚ β”‚
β”‚ + deposit(amount) β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ # calculateInterest() β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ - validatePIN(pin) β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ + getBalance()                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Legend:
+ = Public (accessible everywhere)
# = Protected (for subclasses)
- = Private (internal only)

πŸ’‘ Key Principles

Principle Description Benefit
Encapsulation Hide implementation, expose interface Security & flexibility
Least Privilege Make members as private as possible Reduced coupling
Information Hiding Don't expose internal details Easier maintenance

πŸ”— Associations

Association represents a relationship between two classes where one class uses or interacts with another. It indicates that objects of one class are connected to objects of another class.

πŸ“Š Types of Associations

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          ASSOCIATION TYPES                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                     β”‚
β”‚  1. Inheritance (IS-A)      ⬆️  Strong             β”‚
β”‚     └─ Child inherits from parent                  β”‚
β”‚                                                     β”‚
β”‚  2. Composition (HAS-A)     πŸ”— Strong              β”‚
β”‚     └─ Whole-Part (tightly bound)                  β”‚
β”‚                                                     β”‚
β”‚  3. Aggregation (HAS-A)     πŸ”² Weak                β”‚
β”‚     └─ Whole-Part (loosely bound)                  β”‚
β”‚                                                     β”‚
β”‚  4. Simple Association      ➑️  Medium             β”‚
β”‚     └─ Objects communicate/reference               β”‚
β”‚                                                     β”‚
β”‚  5. Dependency              ⟢ Weak                 β”‚
β”‚     └─ Temporary usage relationship                β”‚
β”‚                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

1️⃣ Inheritance (Class Association / IS-A Relationship)

Definition: A child class inherits properties and methods from a parent class. It's an IS-A relationship.

Notation: Solid line with hollow arrowhead pointing to parent class

When to Use: - Creating specialized versions of a general class - Sharing common behavior among related classes - Building class hierarchies

πŸ“Š Inheritance Diagram: Multi-Level Hierarchy

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚     Vehicle      β”‚
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                    β”‚ - speed: double  β”‚
                    β”‚ - color: String  β”‚
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                    β”‚ + start()        β”‚
                    β”‚ + stop()         β”‚
                    β”‚ + drive()        β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β–³
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚            β”‚            β”‚
                β”‚            β”‚            β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
         β”‚   Car     β”‚  β”‚  Bike   β”‚  β”‚ Truck   β”‚
         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
         β”‚ - doors   β”‚  β”‚ -gears  β”‚  β”‚ -cargo  β”‚
         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
         β”‚ +honk()   β”‚  β”‚+shift() β”‚  β”‚+load()  β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Inheritance: Child extends Parent
Benefits:
βœ“ Code reuse
βœ“ Polymorphism
βœ“ Consistent interface

Example Code

class Vehicle:
    def __init__(self, speed, color):
        self.speed = speed
        self.color = color

    def start(self):
        print("Starting engine...")

    def drive(self):
        print(f"Driving at {self.speed} km/h")

class Car(Vehicle):                    # Inherits from Vehicle
    def __init__(self, speed, color, doors):
        super().__init__(speed, color)
        self.doors = doors

    def honk(self):
        print("Beep! Beep!")

# Usage
car = Car(100, "red", 4)               # Car IS-A Vehicle
car.drive()                            # Inherits from parent
car.honk()                             # Own method

⚠️ Common Mistakes

  • ❌ Using inheritance when composition is better
  • ❌ Creating deep hierarchies (more than 3 levels)
  • ❌ Violating Liskov Substitution Principle
  • βœ… Use inheritance for true IS-A relationships
  • βœ… Prefer composition for HAS-A relationships

2️⃣ Simple Association (Object Association / HAS-A Relationship)

Definition: One object uses or references another object. It's the weakest connection between objects.

Notation: Simple line with or without arrowhead

When to Use: - Objects communicate through references - One object provides services to another - Temporary or optional relationships

πŸ“Š Simple Association Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Student    │────────▢│   Course     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ - name       β”‚ enrolls β”‚ - courseId   β”‚
β”‚ - studentId  β”‚  in     β”‚ - title      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + getName()  β”‚         β”‚ + getName()  β”‚
β”‚ + enroll()   β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Navigation: One-way
Student knows about Course
Course doesn't know about Student

Example Code

class Course:
    def __init__(self, course_id, title):
        self.course_id = course_id
        self.title = title

    def get_title(self):
        return self.title

class Student:
    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id
        self.courses = []  # Reference to Course objects

    def enroll(self, course):
        self.courses.append(course)

    def get_courses(self):
        return [c.get_title() for c in self.courses]

# Usage
math_course = Course(101, "Mathematics")
student = Student("John", 1)
student.enroll(math_course)              # Association created

Characteristics

Aspect Description
Strength Weak - no dependency on lifecycle
Navigation One or Two-way
Multiplicity Can be one-to-one, one-to-many, many-to-many
Flexibility Highly flexible, can be changed at runtime

3️⃣ Composition (Strong IS-PART-OF Relationship)

Definition: A whole-part relationship where parts cannot exist independently. The container owns the parts.

Notation: Solid line with filled diamond on the container side

When to Use: - Whole controls lifecycle of parts - Parts have no meaning outside the whole - Clear ownership and exclusive relationship

πŸ“Š Composition Diagram: Chair Example

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    Chair     β”‚ (Whole)
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                    β”‚ - color      β”‚
                    β”‚ - legs β—Šβ”€β”€β”  β”‚
                    β”‚ - seat  β—Šβ”€β”Όβ”€β”€β”€
                    β”‚ - arms  β—Šβ”€β”˜  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β—Š
                          /|\
                         / | \
                        /  |  \
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚   Leg    β”‚ β”‚  Seat  β”‚ β”‚   Arm    β”‚
        β”‚(Part)    β”‚ β”‚(Part)  β”‚ β”‚ (Part)   β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Composition: Whole owns Parts
Multiplicity:
  Chair has 4 Legs
  Chair has 1 Seat
  Chair has 2 Arms

Lifecycle: If Chair is deleted, all parts are deleted

Example Code

class Leg:
    def __init__(self, material):
        self.material = material

class Seat:
    def __init__(self, material):
        self.material = material

class Arm:
    def __init__(self, material):
        self.material = material

class Chair:
    def __init__(self, color):
        self.color = color
        # Composition: Chair OWNS these parts
        self.legs = [Leg("wood") for _ in range(4)]
        self.seat = Seat("fabric")
        self.arms = [Arm("wood") for _ in range(2)]

    def __del__(self):
        print("Chair deleted - all parts deleted with it")

# Usage
chair = Chair("red")
# When chair is deleted, all parts are automatically deleted
# Parts cannot exist without the chair

Key Characteristics

Property Details
Ownership Container owns parts exclusively
Lifecycle Parts die with container
Multiplicity Fixed (usually 1:many or 1:1)
Independence Parts cannot exist alone
Strength Strongest relationship

4️⃣ Aggregation (Weak HAS-A Relationship)

Definition: A whole-part relationship where parts can exist independently. The container only references the parts.

Notation: Line with unfilled (hollow) diamond on the container side

When to Use: - Parts can exist independently - Whole doesn't control lifecycle of parts - Looser coupling than composition

πŸ“Š Aggregation Diagram: University-Department Example

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   University    β”‚
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                    β”‚ - name          β”‚
                    β”‚ - departments ◇─┼───┐
                    β”‚ - students    ◇─┼──┐│
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚β”‚
                            β—‡            β”‚β”‚
                           / \           β”‚β”‚
                          /   \          β”‚β”‚
                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚   Department     β”‚ β”‚    Student    β”‚
                  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                  β”‚ - name           β”‚ β”‚ - name        β”‚
                  β”‚ - faculty        β”‚ β”‚ - student_id  β”‚
                  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                  β”‚ + getName()      β”‚ β”‚ + getName()   β”‚
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Aggregation: Whole references Parts (not owns)
Multiplicity:
  University HAS MANY Departments
  University HAS MANY Students

Lifecycle: If University is deleted, Departments/Students continue to exist

Example Code

class Department:
    def __init__(self, name):
        self.name = name

    def get_name(self):
        return self.name

class Student:
    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id

class University:
    def __init__(self, name):
        self.name = name
        self.departments = []    # Aggregation: references, not owns
        self.students = []

    def add_department(self, department):
        self.departments.append(department)

    def add_student(self, student):
        self.students.append(student)

# Usage
dept = Department("Computer Science")
student = Student("Alice", 101)
university = University("MIT")
university.add_department(dept)
university.add_student(student)

# Even if university is deleted, department and student still exist
del university
print(dept.get_name())      # βœ“ Still works!
print(student.name)         # βœ“ Still works!

Composition vs Aggregation

Aspect Composition Aggregation
Notation Filled diamond β—† Hollow diamond β—‡
Ownership Container owns parts Container references parts
Lifecycle Parts die with container Parts can outlive container
Independence Parts cannot exist alone Parts can exist independently
Strength Strong Weak
Example Heart IS-PART-OF Body Car HAS-A Engine (replaceable)

πŸ”„ Relationships

πŸ“Š One-Way Association

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Driver    │───────▢│   Vehicle   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ - name      β”‚        β”‚ - licensePlateβ”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + drive()   β”‚        β”‚ + start()   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Navigation: Only Driver knows about Vehicle
Arrow direction shows navigation direction

πŸ“Š Two-Way Association (Bidirectional)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Person     │◄───────────────▢│   Company    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   works for     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ - name       β”‚   employs       β”‚ - name       β”‚
β”‚ - company ───┼────────────────-β”‚ - employees  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + getName()  β”‚                 β”‚ + getName()  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Navigation: Both know about each other
Person knows Company
Company knows all its Employees

Code Example: Two-Way Association

class Company:
    def __init__(self, name):
        self.name = name
        self.employees = []

class Person:
    def __init__(self, name, company):
        self.name = name
        self.company = company              # Reference to Company
        self.company.employees.append(self) # Company knows Person

# Usage
company = Company("Google")
person = Person("John", company)
person2 = Person("Jane", company)

print(person.company.name)          # Personβ†’Company βœ“
print(len(company.employees))       # Companyβ†’Persons βœ“

Multiplicity

Notation Meaning Example
1 Exactly one Each order has exactly 1 customer
0..1 Zero or one Optional relationship
* or 0..* Zero or many Order can have many items
1..* One or many Author has at least 1 book
n Specific number Deck has 52 cards

πŸ“Š Multiplicity Examples

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” 1        * β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Customer  │────────────│    Order     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  One customer can have many orders
  Each order belongs to one customer


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” 0..1    1..* β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Teacher │────────────────│  Student    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  A teacher may teach 1 to many students
  A student must have 1 to many teachers

πŸ”€ Dependency

Definition: One class depends on another class for its implementation. The dependency exists when a class uses another class temporarily.

Notation: Dashed line with arrow pointing to the dependent class

When to Use: - Temporary relationships - A method receives an object as parameter - Weak coupling is desired - Usage is limited to specific operations

πŸ“Š Dependency Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚RegistrationMgr  β”‚- - - - β–Άβ”‚  Student    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ uses   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ - students[]     β”‚        β”‚ - name      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚+ register(s)     β”‚        β”‚ + getName() β”‚
β”‚+ unregister(s)   β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Dependency: Dashed line
RegistrationMgr depends on Student
(usually as method parameter or temporary usage)

Example Code

from typing import List

class Student:
    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id

class Course:
    def __init__(self, course_id, title):
        self.course_id = course_id
        self.title = title
        self.students: List[Student] = []

class RegistrationManager:
    def register_student(self, student: Student, course: Course):
        """
        Dependency: Uses Student object as parameter
        Temporary usage - doesn't own the Student
        """
        course.students.append(student)
        print(f"{student.name} registered in {course.title}")

    def generate_report(self, course: Course) -> str:
        """
        Another dependency usage
        """
        return f"Total students: {len(course.students)}"

# Usage
student = Student("Bob", 1)
course = Course(101, "Python")
manager = RegistrationManager()

# RegistrationManager depends on Student object
manager.register_student(student, course)
report = manager.generate_report(course)

Dependency vs Association

Aspect Dependency Association
Lifetime Temporary Persistent
Notation Dashed line Solid line
Coupling Weak Strong
Usage Method parameter Object attribute
Example sendEmail(person) Student enrolled in Course

🌍 Real-World Examples

Example 1: E-Commerce System

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   E-COMMERCE SYSTEM                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   Customer   β”‚
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                    β”‚ - name       β”‚
                    β”‚ - email      β”‚
                    β”‚ - address ◇──┼─┐
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
                           β–³         β”‚
                           β”‚         β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”   β”‚
                    β”‚  Premium   β”‚   β”‚
                    β”‚ Customer   β”‚   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                                     β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚                            β”‚
        β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                    β”‚    Address     β”‚
        β”‚                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚                    β”‚ - street       β”‚
        β”‚                    β”‚ - city         β”‚
        β”‚                    β”‚ - country      β”‚
        β”‚                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β”‚ 1        *
    β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚        Order            β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ - orderId               │◆─┐
    β”‚ - items: List[Item]     β”‚  β”‚ Composition
    β”‚ - totalPrice            β”‚  β”‚ Order OWNS items
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
    β”‚ + calculateTotal()      β”‚  β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
             β–³                    β”‚
             β”‚                    β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
    β”‚   Item            β”‚        β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€        β”‚
    β”‚ - itemId          β”‚        β”‚
    β”‚ - quantity        β”‚        β”‚
    β”‚ - product β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚ - price           β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ + getTotal()      β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
             β–³
             β”‚
        β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”
        β”‚ Product β”‚
        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚ - name  β”‚
        β”‚ - price β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Relationships:
βœ“ Customer IS-A Entity (Inheritance to Premium Customer)
βœ“ Customer HAS-A Address (Aggregation)
βœ“ Customer HAS-MANY Orders (Aggregation)
βœ“ Order OWNS Items (Composition)
βœ“ Item references Product (Association)

Example 2: Library Management System

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      LIBRARY MANAGEMENT SYSTEM              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   Library    β”‚
            β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
            β”‚ - name       β”‚
            β”‚ - address    β”‚
            β”‚ - books ◇────┼──────┐
            β”‚ - members ◇──┼───┐  β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β”‚
                    β–³          β”‚  β”‚
                    β”‚          β”‚  β”‚
             β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”   β”Œβ”€β”€β”€β”΄β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”
             β”‚ Member  β”‚   β”‚    Book      β”‚
             β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
             β”‚ - id    β”‚   β”‚ - isbn       β”‚
             β”‚ - name  β”‚   β”‚ - title      β”‚
             β”‚ - books β”‚   β”‚ - author ────┼──┐
             β”‚   ◆─────┼─┐ β”‚ - status     β”‚  β”‚
             └────────── β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                       β”‚ β”‚                   β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚               β”‚        β”‚
    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ BorrowRecordβ”‚ β”‚    Author     β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ - dateOut   β”‚ β”‚ - name        β”‚
    β”‚ - dueDate   β”‚ β”‚ - country     β”‚
    β”‚ - dateReturnβ”‚ β”‚ - biography   β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Relationships:
βœ“ Library HAS-MANY Books (Aggregation)
βœ“ Library HAS-MANY Members (Aggregation)
βœ“ Member BORROWS Books (Association)
βœ“ Member HAS-MANY BorrowRecords (Composition)
βœ“ Book written by Author (Association)

🎯 Interview Questions

Basic Level

Q1: What is the difference between association and aggregation?

Answer:

Aspect Association Aggregation
Relationship General relationship Whole-Part relationship
Strength Weaker Slightly stronger
Notation Simple line Hollow diamond
Lifecycle No specific binding Parts can exist independently
Example Student enrolls in Course Library HAS Books

Key Point: Aggregation is a special type of association with "HAS-A" semantics.


Q2: When would you use inheritance vs composition?

Answer:

Use Inheritance (IS-A) when: - There's a true "is-a" relationship (Dog IS-A Animal) - You want to share common behavior - You need polymorphism - The relationship is stable and fundamental

Use Composition (HAS-A) when: - You want flexible object creation - Relationships might change at runtime - You want to avoid deep hierarchies - Avoiding "Gorilla-Banana problem"

Example:

# βœ“ Good: Inheritance
class Animal:
    def eat(self):
        pass

class Dog(Animal):          # Dog IS-A Animal
    pass

# βœ“ Better: Composition for flexibility
class Dog:
    def __init__(self):
        self.behavior = Behavior()  # Can change at runtime

    def eat(self):
        self.behavior.eat()

Q3: Explain the difference between composition and aggregation with an example.

Answer:

Composition (Strong relationship):

Car OWNS Engine
β”œβ”€ If Car is destroyed β†’ Engine is destroyed
β”œβ”€ Parts cannot exist independently
└─ Solid diamond (β—†) notation

Aggregation (Weak relationship):

Library HAS Books
β”œβ”€ If Library is destroyed β†’ Books still exist
β”œβ”€ Parts can exist independently
└─ Hollow diamond (β—‡) notation

Real-world analogy: - Composition: Body composed of organs (organs die if body dies) - Aggregation: Team has players (players exist even if team dissolves)


Intermediate Level

Q4: What is the difference between dependency and association?

Answer:

Aspect Dependency Association
Strength Very Weak Stronger
Notation Dashed line Solid line
Lifetime Temporary Persistent
Usage Method parameter Object attribute
Coupling Loose Tight
Example sendEmail(user) user.address

Code Example:

# Dependency: Temporary usage
def send_notification(user: User, msg: Message):  # Parameter
    print(f"Sending to {user.name}")

# Association: Persistent relationship
class User:
    def __init__(self):
        self.email = Email()  # Persistent attribute

Q5: How would you model a library management system with class diagrams?

Answer:

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   Library    β”‚
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                    β”‚ - name       β”‚
                    β”‚ - books ◇────┼───┐
                    β”‚ - members ◇───   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                           β–³           β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”    β”‚
                    β”‚Member       β”‚    β”‚
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€    β”‚
                    β”‚ - name      β”‚    β”‚
                    β”‚ - memberId  β”‚    β”‚
                    β”‚ - borrowed◆─┼──┐ β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ β”‚
                                     β”‚ β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”˜
        β”‚                            β”‚
        β”‚               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”
        β”‚               β”‚     Book      β”‚
        β”‚               β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚               β”‚ - isbn        β”‚
        β”‚               β”‚ - title       β”‚
        β”‚               β”‚ - author ───┐ β”‚
        β”‚               β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚               β”‚ + getDetails()β”‚
        β”‚               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                        β–³
        β”‚                        β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚      Author            β”‚
         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
         β”‚ - name                 β”‚
         β”‚ - country              β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Relationships:
βœ“ Library HAS-MANY Books (Aggregation) - Books exist independently
βœ“ Library HAS-MANY Members (Aggregation) - Members exist independently
βœ“ Member BORROWED Books (Association with multiplicity)
βœ“ Book written by Author (Association)

Q6: Explain the Liskov Substitution Principle with inheritance example.

Answer:

LSP: Objects of a superclass should be replaceable with objects of its subclasses without breaking the application.

βœ“ Good Example:

class Bird:
    def fly(self):
        return "Flying"

class Eagle(Bird):
    def fly(self):
        return "Soaring high"

class Sparrow(Bird):
    def fly(self):
        return "Flying fast"

# Can substitute any Bird with its subclass
birds: List[Bird] = [Eagle(), Sparrow()]
for bird in birds:
    print(bird.fly())  # Works correctly

❌ Bad Example:

class Bird:
    def fly(self):
        return "Flying"

class Penguin(Bird):
    def fly(self):
        raise Exception("Penguins can't fly!")  # Violates LSP!

# This breaks the contract
penguin: Bird = Penguin()
penguin.fly()  # Unexpected error

Solution:

class Bird:
    pass

class FlyingBird(Bird):
    def fly(self):
        pass

class SwimmingBird(Bird):
    def swim(self):
        pass

class Penguin(SwimmingBird):  # Correct inheritance
    def swim(self):
        return "Swimming"

Advanced Level

Q7: Design a class diagram for a ride-sharing application (like Uber).

Answer:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              RIDE-SHARING APPLICATION                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚      User        β”‚
                    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                    β”‚ - userId         β”‚
                    β”‚ - name           β”‚
                    β”‚ - phone          β”‚
                    β”‚ - ratings        β”‚
                    β”‚ - location ◇─────┼──┐
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                             β–³            β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚                    β”‚            β”‚
        β”‚            β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”   β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
        β”‚            β”‚ Passenger β”‚   β”‚  Driver  β”‚
        β”‚            β”‚           β”‚   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚ - vehicleβ”‚
        β”‚                            β”‚ -license β”‚
        β”‚                            β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
        β”‚                                 β”‚
        β”‚                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
        β”‚                        β”‚    Vehicle    β”‚
        β”‚                        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
        β”‚                        β”‚ - licensePlateβ”‚
        β”‚                        β”‚ - model       β”‚
        β”‚                        β”‚ - capacity    β”‚
        β”‚                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β”‚ 1        *
    β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚        Ride              β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ - rideId                 β”‚
    β”‚ - pickupLocation ◇───┐   β”‚
    β”‚ - dropoffLocation ◇──┼─┐ β”‚
    β”‚ - startTime          β”‚ β”‚ β”‚
    β”‚ - endTime            β”‚ β”‚ β”‚
    β”‚ - fare               β”‚ β”‚ β”‚
    β”‚ - status             β”‚ β”‚ β”‚
    β”‚ - driver β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”˜ β”‚
    β”‚ - passenger β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ + calculateFare()        β”‚
    β”‚ + updateStatus()         β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Relationships:
βœ“ Passenger/Driver IS-A User (Inheritance)
βœ“ Driver HAS-A Vehicle (Composition) - Driver must have vehicle
βœ“ Ride HAS-MANY Locations (Composition)
βœ“ Ride references Driver & Passenger (Association)
βœ“ Ride tracks pickupLocation & dropoffLocation (Dependency)

Q8: What are the advantages and disadvantages of deep inheritance hierarchies?

Answer:

Disadvantages of Deep Hierarchies: - ❌ Hard to understand and maintain - ❌ Fragile base class problem - ❌ Difficult to add new variations - ❌ Risk of misusing inherited methods - ❌ Violates Single Responsibility Principle

Advantages: - βœ“ Code reuse at multiple levels - βœ“ Clear hierarchical organization (sometimes) - βœ“ Enforces consistency

Best Practice:

Keep hierarchies shallow (max 3 levels)
Level 0: Base class (Animal)
Level 1: Intermediate (Mammal)
Level 2: Concrete (Dog) ← Stop here!

Better Approach - Composition:

# Instead of: Dog -> Animal -> LivingBeing -> ...
# Use composition:

class Dog:
    def __init__(self):
        self.behavior = AnimalBehavior()
        self.movement = FourLeggedMovement()
        self.diet = CarnivoreeDiet()

πŸ“ Summary Table

Concept Symbol Strength When to Use
Inheritance β–³ Strong IS-A relationship
Composition β—† Strong Whole owns parts
Aggregation β—‡ Weak Whole references parts
Association β†’ Medium Objects interact
Dependency - - -β–Ί Weak Temporary usage

πŸš€ Quick Decision Tree

Do classes have an IS-A relationship?
β”œβ”€ YES β†’ Use Inheritance (β–³)
└─ NO β†’ Continue to next question

Does one class own/create the other?
β”œβ”€ YES β†’ Use Composition (β—†)
└─ NO β†’ Continue to next question

Can parts exist without the whole?
β”œβ”€ YES β†’ Use Aggregation (β—‡)
└─ NO β†’ Use Association (β†’)

Is the relationship temporary/parameter-based?
β”œβ”€ YES β†’ Use Dependency (- - -β–Ί)
└─ NO β†’ Use Association (β†’)

πŸ“š References & Further Reading

  • UML Specification by OMG
  • "Design Patterns" by Gang of Four
  • "Head First Design Patterns"
  • "Refactoring" by Martin Fowler
  • "Clean Architecture" by Robert C. Martin
  • "Object-Oriented Design in Java" by Stephen Cole