All Together
See all relationships working together in a real-world system.
Let’s build a complete Library Management System that demonstrates all four class relationships working together.
System Overview
Section titled “System Overview”We’ll design a library system with:
- Library (main system)
- Book (items in library)
- Member (people who borrow books)
- Librarian (staff managing library)
- Loan (borrowing record)
- Fine (penalty for late returns)
Complete Implementation
Section titled “Complete Implementation”from abc import ABC, abstractmethodfrom datetime import datetime, timedelta
# ========== INHERITANCE ==========class Person(ABC): """Base class using Inheritance""" def __init__(self, name: str, email: str): self.name = name self.email = email
@abstractmethod def get_role(self): pass
# Inheritance - Member IS-A Personclass Member(Person): def __init__(self, name: str, email: str, member_id: str): super().__init__(name, email) self.member_id = member_id self.loans = [] # COMPOSITION - loans belong to member
def get_role(self): return "Member"
def borrow_book(self, book, librarian): # DEPENDENCY - uses Book and Librarian temporarily loan = Loan(self, book, librarian) self.loans.append(loan) # COMPOSITION return loan
# Inheritance - Librarian IS-A Personclass Librarian(Person): def __init__(self, name: str, email: str, employee_id: str): super().__init__(name, email) self.employee_id = employee_id
def get_role(self): return "Librarian"
def process_return(self, loan): # DEPENDENCY - uses Loan temporarily loan.return_book() if loan.is_overdue(): fine = Fine(loan) # COMPOSITION - fine created with loan loan.fine = fine
# ========== COMPOSITION ==========class Book: """Book is part of Library - COMPOSITION""" def __init__(self, isbn: str, title: str, author: str): self.isbn = isbn self.title = title self.author = author self.available = True
# COMPOSITION - Loan belongs to Memberclass Loan: def __init__(self, member, book, librarian): self.member = member # ASSOCIATION - references member self.book = book # ASSOCIATION - references book self.librarian = librarian # ASSOCIATION - references librarian self.borrow_date = datetime.now() self.due_date = self.borrow_date + timedelta(days=14) self.return_date = None self.fine = None # COMPOSITION - optional fine
def return_book(self): self.return_date = datetime.now() self.book.available = True
def is_overdue(self): if self.return_date: return self.return_date > self.due_date return datetime.now() > self.due_date
# COMPOSITION - Fine belongs to Loanclass Fine: def __init__(self, loan): self.loan = loan # ASSOCIATION - references loan days_overdue = (datetime.now() - loan.due_date).days self.amount = days_overdue * 0.50 # $0.50 per day
# ========== COMPOSITION & AGGREGATION ==========class Library: """Library contains Books (COMPOSITION) and has Members/Librarians (AGGREGATION)""" def __init__(self, name: str): self.name = name self.books = [] # COMPOSITION - books belong to library self.members = [] # AGGREGATION - members can exist independently self.librarians = [] # AGGREGATION - librarians can exist independently
def add_book(self, book): self.books.append(book) # COMPOSITION
def register_member(self, member): self.members.append(member) # AGGREGATION
def hire_librarian(self, librarian): self.librarians.append(librarian) # AGGREGATION
def find_book(self, isbn: str): """DEPENDENCY - uses string parameter""" for book in self.books: if book.isbn == isbn: return book return None
# ========== USAGE ==========# Create librarylibrary = Library("City Library")
# Create books (COMPOSITION - belong to library)book1 = Book("12345", "Python Guide", "Author A")book2 = Book("67890", "Java Guide", "Author B")library.add_book(book1)library.add_book(book2)
# Create members (AGGREGATION - can exist independently)member1 = Member("Alice", "alice@example.com", "M001")member2 = Member("Bob", "bob@example.com", "M002")library.register_member(member1)library.register_member(member2)
# Create librarian (AGGREGATION)librarian = Librarian("Carol", "carol@library.com", "L001")library.hire_librarian(librarian)
# Member borrows book (creates ASSOCIATION and COMPOSITION)loan = member1.borrow_book(book1, librarian)print(f"{member1.name} borrowed {book1.title}")
# Librarian processes return (uses DEPENDENCY)librarian.process_return(loan)print(f"Book returned. Fine: ${loan.fine.amount if loan.fine else 0:.2f}")import java.time.LocalDateTime;import java.time.temporal.ChronoUnit;import java.util.ArrayList;import java.util.List;
// ========== INHERITANCE ==========abstract class Person { protected String name; protected String email;
public Person(String name, String email) { this.name = name; this.email = email; }
public abstract String getRole();}
// Inheritance - Member IS-A Personclass Member extends Person { private String memberId; private List<Loan> loans; // COMPOSITION - loans belong to member
public Member(String name, String email, String memberId) { super(name, email); this.memberId = memberId; this.loans = new ArrayList<>(); }
@Override public String getRole() { return "Member"; }
// DEPENDENCY - uses Book and Librarian temporarily public Loan borrowBook(Book book, Librarian librarian) { Loan loan = new Loan(this, book, librarian); loans.add(loan); // COMPOSITION return loan; }}
// Inheritance - Librarian IS-A Personclass Librarian extends Person { private String employeeId;
public Librarian(String name, String email, String employeeId) { super(name, email); this.employeeId = employeeId; }
@Override public String getRole() { return "Librarian"; }
// DEPENDENCY - uses Loan temporarily public void processReturn(Loan loan) { loan.returnBook(); if (loan.isOverdue()) { Fine fine = new Fine(loan); // COMPOSITION - fine created with loan loan.setFine(fine); } }}
// ========== COMPOSITION ==========class Book { private String isbn; private String title; private String author; private boolean available;
public Book(String isbn, String title, String author) { this.isbn = isbn; this.title = title; this.author = author; this.available = true; }
public String getTitle() { return title; }
public boolean isAvailable() { return available; }
public void setAvailable(boolean available) { this.available = available; }}
// COMPOSITION - Loan belongs to Memberclass Loan { private Member member; // ASSOCIATION - references member private Book book; // ASSOCIATION - references book private Librarian librarian; // ASSOCIATION - references librarian private LocalDateTime borrowDate; private LocalDateTime dueDate; private LocalDateTime returnDate; private Fine fine; // COMPOSITION - optional fine
public Loan(Member member, Book book, Librarian librarian) { this.member = member; this.book = book; this.librarian = librarian; this.borrowDate = LocalDateTime.now(); this.dueDate = borrowDate.plusDays(14); }
public void returnBook() { this.returnDate = LocalDateTime.now(); book.setAvailable(true); }
public boolean isOverdue() { if (returnDate != null) { return returnDate.isAfter(dueDate); } return LocalDateTime.now().isAfter(dueDate); }
public void setFine(Fine fine) { this.fine = fine; }}
// COMPOSITION - Fine belongs to Loanclass Fine { private Loan loan; // ASSOCIATION - references loan private double amount;
public Fine(Loan loan) { this.loan = loan; long daysOverdue = ChronoUnit.DAYS.between(loan.dueDate, LocalDateTime.now()); this.amount = daysOverdue * 0.50; // $0.50 per day }
public double getAmount() { return amount; }}
// ========== COMPOSITION & AGGREGATION ==========class Library { private String name; private List<Book> books; // COMPOSITION - books belong to library private List<Member> members; // AGGREGATION - members can exist independently private List<Librarian> librarians; // AGGREGATION - librarians can exist independently
public Library(String name) { this.name = name; this.books = new ArrayList<>(); this.members = new ArrayList<>(); this.librarians = new ArrayList<>(); }
public void addBook(Book book) { books.add(book); // COMPOSITION }
public void registerMember(Member member) { members.add(member); // AGGREGATION }
public void hireLibrarian(Librarian librarian) { librarians.add(librarian); // AGGREGATION }
// DEPENDENCY - uses string parameter public Book findBook(String isbn) { for (Book book : books) { if (book.getIsbn().equals(isbn)) { return book; } } return null; }}
// ========== USAGE ==========public class Main { public static void main(String[] args) { // Create library Library library = new Library("City Library");
// Create books (COMPOSITION - belong to library) Book book1 = new Book("12345", "Python Guide", "Author A"); Book book2 = new Book("67890", "Java Guide", "Author B"); library.addBook(book1); library.addBook(book2);
// Create members (AGGREGATION - can exist independently) Member member1 = new Member("Alice", "alice@example.com", "M001"); Member member2 = new Member("Bob", "bob@example.com", "M002"); library.registerMember(member1); library.registerMember(member2);
// Create librarian (AGGREGATION) Librarian librarian = new Librarian("Carol", "carol@library.com", "L001"); library.hireLibrarian(librarian);
// Member borrows book (creates ASSOCIATION and COMPOSITION) Loan loan = member1.borrowBook(book1, librarian); System.out.println(member1.name + " borrowed " + book1.getTitle());
// Librarian processes return (uses DEPENDENCY) librarian.processReturn(loan); System.out.println("Book returned. Fine: $" + (loan.fine != null ? loan.fine.getAmount() : 0)); }}Relationship Summary
Section titled “Relationship Summary”Relationship Breakdown
Section titled “Relationship Breakdown”1. Inheritance (Person → Member, Librarian)
Section titled “1. Inheritance (Person → Member, Librarian)”- Why: Both share common attributes (name, email) and have roles
- Type: “Is-a” relationship
2. Composition (Library → Book, Member → Loan, Loan → Fine)
Section titled “2. Composition (Library → Book, Member → Loan, Loan → Fine)”- Why: Books are part of library, loans belong to members, fines belong to loans
- Type: Strong ownership, cannot exist independently
3. Aggregation (Library → Member, Library → Librarian)
Section titled “3. Aggregation (Library → Member, Library → Librarian)”- Why: Members and librarians can exist independently (can transfer/leave)
- Type: Weak ownership, independent lifecycle
4. Association (Loan → Member, Book, Librarian)
Section titled “4. Association (Loan → Member, Book, Librarian)”- Why: Loan references these classes but doesn’t own them
- Type: “Knows-a” relationship
5. Dependency (Member → Book, Librarian → Loan)
Section titled “5. Dependency (Member → Book, Librarian → Loan)”- Why: Used temporarily as method parameters
- Type: Temporary use, no storage