💡 Library acts as the system facade coordinating all operations.
insert
Add method to add books to Library
We add add_book method to Library to insert new books or add copies if the book exists.
💡 This method handles the edge case of multiple copies and avoids duplicate book entries.
Line:def add_book(self, title, author, isbn, num_copies):
if isbn not in self.books:
book = Book(title, author, isbn)
self.books[isbn] = book
else:
book = self.books[isbn]
for i in range(num_copies):
copy_id = f"{isbn}_{len(book.copies)+1}"
book.copies.append(BookCopy(copy_id))
💡 Efficiently manages inventory by reusing existing book objects and adding copies.
insert
Add method to register users
We add register_user method to Library to add new users with roles.
💡 User registration is essential for managing borrow permissions and tracking loans.
Line:def register_user(self, user_id, name, role):
if user_id not in self.users:
self.users[user_id] = User(user_id, name, role)
💡 Ensures unique users and supports role-based access.
insert
Add method to loan a book copy
We add loan_book method to Library to loan an available copy of a book to a user.
💡 This method handles checking availability and creating a Loan record.
Line:def loan_book(self, isbn, user_id, loan_date):
if isbn not in self.books or user_id not in self.users:
return false
book = self.books[isbn]
user = self.users[user_id]
for copy in book.copies:
if copy.is_available:
copy.is_available = false
loan = Loan(copy, user, loan_date)
self.loans.append(loan)
return true
return false
💡 Demonstrates traversal and conditional logic to enforce availability constraints.
insert
Add method to return a book copy
We add return_book method to Library to mark a loaned copy as returned and update the loan record.
💡 Returning books updates availability and loan return date, critical for inventory accuracy.
Line:def return_book(self, copy_id, return_date):
for loan in self.loans:
if loan.book_copy.copy_id == copy_id and loan.return_date is null:
loan.return_date = return_date
loan.book_copy.is_available = true
return true
return false
💡 Shows traversal and state update to handle returns correctly.
prune
Add edge case handling for invalid operations
We add checks in loan_book and return_book to handle invalid ISBNs, user IDs, and copy IDs gracefully.
💡 Edge case handling prevents system crashes and ensures robustness.
Line:if isbn not in self.books or user_id not in self.users:
return false
# In return_book
if loan.book_copy.copy_id != copy_id or loan.return_date is not null:
continue
💡 Robust design anticipates and safely handles invalid or unexpected inputs.
reconstruct
Summary: Final class diagram state
The final design includes Book, BookCopy, User, Loan, and Library classes with their fields, methods, and relationships fully defined.
💡 This final state shows the complete system design ready for implementation.
💡 The design balances encapsulation, composition, and association to model a real-world library system.
class Book: # STEP 1
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.copies = []
class BookCopy: # STEP 2
def __init__(self, copy_id):
self.copy_id = copy_id
self.is_available = true
class User: # STEP 3
def __init__(self, user_id, name, role):
self.user_id = user_id
self.name = name
self.role = role
class Loan: # STEP 4
def __init__(self, book_copy, user, loan_date):
self.book_copy = book_copy
self.user = user
self.loan_date = loan_date
self.return_date = null
class Library: # STEP 5
def __init__(self):
self.books = {}
self.users = {}
self.loans = []
def add_book(self, title, author, isbn, num_copies): # STEP 6
if isbn not in self.books:
book = Book(title, author, isbn)
self.books[isbn] = book
else:
book = self.books[isbn]
for i in range(num_copies):
copy_id = f"{isbn}_{len(book.copies)+1}"
book.copies.append(BookCopy(copy_id))
def register_user(self, user_id, name, role): # STEP 7
if user_id not in self.users:
self.users[user_id] = User(user_id, name, role)
def loan_book(self, isbn, user_id, loan_date): # STEP 8
if isbn not in self.books or user_id not in self.users:
return false
book = self.books[isbn]
user = self.users[user_id]
for copy in book.copies:
if copy.is_available:
copy.is_available = false
loan = Loan(copy, user, loan_date)
self.loans.append(loan)
return true
return false
def return_book(self, copy_id, return_date): # STEP 9
for loan in self.loans:
if loan.book_copy.copy_id == copy_id and loan.return_date is null:
loan.return_date = return_date
loan.book_copy.is_available = true
return true
return false
# STEP 10: Edge case handling is integrated in loan_book and return_book methods
📊
Design a Library Management System - LLD with Relationships & Edge Cases - Watch the Algorithm Execute, Step by Step
Watching the design unfold step-by-step reveals how each class responsibility and relationship is established, making the system's structure clear without reading dense code.
Step 1/11
·Active fill★Answer cell
Encapsulation of book attributes and inventory management.
Book
−title: string
−author: string
−isbn: string
−copies: List[BookCopy]
+__init__()
Composition relationship: Book owns multiple BookCopies.
Book
−title: string
−author: string
−isbn: string
−copies: List[BookCopy]
+__init__()
BookCopy
−copy_id: string
−is_available: bool
+__init__()
Book ◆ BookCopy (1:0..*)
User class encapsulates identity and role for access control.
Book
−title: string
−author: string
−isbn: string
−copies: List[BookCopy]
+__init__()
BookCopy
−copy_id: string
−is_available: bool
+__init__()
User
−user_id: string
−name: string
−role: string
+__init__()
Book ◆ BookCopy (1:0..*)
Loan associates BookCopy and User with temporal data.
Book
−title: string
−author: string
−isbn: string
−copies: List[BookCopy]
+__init__()
BookCopy
−copy_id: string
−is_available: bool
+__init__()
User
−user_id: string
−name: string
−role: string
+__init__()
Loan
−book_copy: BookCopy
−user: User
−loan_date: date
−return_date: date|null
+__init__()
Book ◆ BookCopy (1:0..*)Loan → BookCopy (1:1)Loan → User (1:1)
Library aggregates all main entities and manages system state.
Book
−title: string
−author: string
−isbn: string
−copies: List[BookCopy]
+__init__()
BookCopy
−copy_id: string
−is_available: bool
+__init__()
User
−user_id: string
−name: string
−role: string
+__init__()
Loan
−book_copy: BookCopy
−user: User
−loan_date: date
−return_date: date|null
+__init__()
Library
−books: Dict[string, Book]
−users: Dict[string, User]
−loans: List[Loan]
+__init__()
Book ◆ BookCopy (1:0..*)Loan → BookCopy (1:1)Loan → User (1:1)Library ◇ Book (1:0..*)Library ◇ User (1:0..*)Library ◇ Loan (1:0..*)
Method handles book insertion and copy management.
Library
−books: Dict[string, Book]
−users: Dict[string, User]
−loans: List[Loan]
+add_book()
Library ◇ Book (1:0..*)
Method manages user registration with uniqueness check.
Library
−books: Dict[string, Book]
−users: Dict[string, User]
−loans: List[Loan]
+register_user()
Library ◇ User (1:0..*)
Method enforces availability and user validation before loaning.
Library
−books: Dict[string, Book]
−users: Dict[string, User]
−loans: List[Loan]
+loan_book()
Library ◇ Book (1:0..*)Library ◇ User (1:0..*)Library ◇ Loan (1:0..*)
Method updates loan and copy status upon return.
Library
−books: Dict[string, Book]
−users: Dict[string, User]
−loans: List[Loan]
+return_book()
Library ◇ Loan (1:0..*)
Edge case checks improve system reliability.
Library
−books: Dict[string, Book]
−users: Dict[string, User]
−loans: List[Loan]
+loan_book()
+return_book()
Complete system design with all classes and relationships.
Book
−title: string
−author: string
−isbn: string
−copies: List[BookCopy]
+__init__()
BookCopy
−copy_id: string
−is_available: bool
+__init__()
User
−user_id: string
−name: string
−role: string
+__init__()
Loan
−book_copy: BookCopy
−user: User
−loan_date: date
−return_date: date|null
+__init__()
Library
−books: Dict[string, Book]
−users: Dict[string, User]
−loans: List[Loan]
+add_book()
+register_user()
+loan_book()
+1 more
Book ◆ BookCopy (1:0..*)Loan → BookCopy (1:1)Loan → User (1:1)Library ◇ Book (1:0..*)Library ◇ User (1:0..*)Library ◇ Loan (1:0..*)
Key Takeaways
✓ The design clearly separates entities (Book, BookCopy, User, Loan) and their responsibilities.
This separation is hard to grasp from code alone but is visually clear in the class diagram.
✓ Composition and aggregation relationships model ownership and associations effectively.
Seeing these relationships visually helps understand how objects are linked and managed.
✓ Edge case handling is integrated into methods to ensure robustness without complicating the core design.
Visualizing these checks clarifies how the system avoids invalid operations gracefully.
Practice
(1/5)
1. You need to create different types of vehicles (cars, bikes) that share a common interface, and sometimes you want to create entire families of related vehicles (e.g., electric car + electric bike) ensuring consistency. Which design pattern best fits this requirement?
easy
A. Builder Pattern, because it constructs complex objects step-by-step.
B. Abstract Factory Pattern, because it creates families of related objects ensuring consistency.
C. Factory Pattern, because it creates simple objects based on a type parameter.
D. Singleton Pattern, because it ensures only one instance of each vehicle type.
Solution
Step 1: Understand the requirement for families of related objects
The problem states the need to create related vehicles (e.g., electric car and electric bike) that belong to a family and must be consistent.
Step 2: Match pattern to requirement
Abstract Factory is designed to create families of related objects, ensuring that the created objects are compatible and consistent.
Final Answer:
Option B -> Option B
Quick Check:
Abstract Factory creates related object families, Factory creates single objects [OK]
Hint: Families of related objects -> Abstract Factory [OK]
Common Mistakes:
Confusing Factory with Abstract Factory
Using Builder for simple object creation
2. Which of the following statements about using inheritance to model different vehicle types in the parking lot system is INCORRECT?
medium
A. Inheritance allows sharing common vehicle attributes and behaviors in a base Vehicle class
B. Using inheritance for vehicle types can lead to rigid designs that are hard to extend with new types
C. Inheritance is always the best approach to add new vehicle types without modifying existing code
D. Polymorphism enables treating all vehicle types uniformly when allocating parking spots
Solution
Step 1: Review inheritance benefits
Inheritance supports code reuse and polymorphism for uniform handling.
Step 2: Recognize limitations
Inheritance hierarchies can become rigid and hard to extend, violating open-closed principle.
Step 3: Identify incorrect statement
Claiming inheritance is always best ignores alternatives like composition or interfaces that improve extensibility.
Final Answer:
Option C -> Option C
Quick Check:
Inheritance is not always best for extensibility [OK]
Hint: Inheritance can cause rigidity; prefer composition for extensibility [OK]
Common Mistakes:
Assuming inheritance is always the best design choice
Ignoring polymorphism benefits
3. What is the time complexity of accessing the singleton instance using the double-checked locking pattern in a multithreaded environment after the instance has been initialized?
medium
A. O(1) because synchronization is bypassed after initialization
B. O(log n) due to locking mechanisms involved
C. O(n) due to synchronization overhead on every access
D. O(n^2) if multiple threads contend simultaneously
Synchronization occurs only during the first initialization; subsequent calls skip locking due to the volatile check.
Step 2: Analyze time complexity after initialization
After initialization, the instance is returned immediately without synchronization, so access is constant time.
Final Answer:
Option A -> Option A
Quick Check:
Locking overhead is avoided after first init, so O(1) access [OK]
Hint: Locking only on first access -> O(1) after init [OK]
Common Mistakes:
Assuming synchronization on every call
Confusing locking cost with algorithmic complexity
Overestimating contention impact
4. What is the time complexity of calling the prepare_recipe method in the Template Method Pattern implementation for a beverage, assuming each step runs in constant time?
medium
A. O(1), since the number of steps is fixed and each step runs in constant time
B. O(log n), due to the hook method optimizing optional steps
C. O(n^2), because each step may call other steps recursively
D. O(n), where n is the number of steps in the recipe
Solution
Step 1: Identify number of steps
The template method defines a fixed sequence of steps (boil_water, brew, pour_in_cup, add_condiments).
Step 2: Analyze step execution time
Each step runs in constant time; the hook method only conditionally calls add_condiments but does not affect asymptotic complexity.
Final Answer:
Option D -> Option D
Quick Check:
Fixed steps with constant time each -> O(1) total [OK]
Hint: Fixed step count -> constant time complexity [OK]
Common Mistakes:
Confusing n as input size
Assuming recursion adds complexity
5. If the Composite pattern iterator is extended to allow reusing leaf components multiple times during traversal (e.g., shared leaves), which modification is necessary to ensure correct iteration without infinite loops?
hard
A. No change needed; the existing iterator handles reuse naturally.
B. Modify the iterator to push children in original order instead of reversed order.
C. Add a visited set to track and skip already visited components during iteration.
D. Convert the iterator to a recursive traversal to handle reuse correctly.
Solution
Step 1: Understand reuse implications
Reusing leaves means the same component can appear multiple times, risking infinite loops.
Step 2: Identify solution to prevent infinite loops
Tracking visited components prevents revisiting the same node repeatedly during iteration.
Final Answer:
Option C -> Option C
Quick Check:
Visited set avoids infinite loops with shared components [OK]
Hint: Track visited nodes to handle shared components safely [OK]
Common Mistakes:
Assuming no changes needed
Changing push order does not fix reuse loops
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.