Roadmap › Low-Level Design (LLD) — Object Design, UML and Classic Problems in C# › Module: Classic LLD Problems
Lessons in this course (8)
5. Design a library management system
Intermediate★ Must knowLesson 5 of 8
Requirements: books with many copies; members borrow (max 5) and return; due date 14 days; fines for late returns; reservations when no copy is free; search by title/author.
csharp
public sealed class Book(string isbn, string title, string author) { public string Isbn = isbn, Title = title, Author = author; }
public enum CopyStatus { Available, Loaned, Reserved, Lost }
public sealed class BookCopy(string barcode, Book book) { public string Barcode = barcode; public Book Book = book; public CopyStatus Status = CopyStatus.Available; }
public sealed class Member(int id, string name) { public int Id = id; public string Name = name; public List<Loan> Loans { get; } = []; }
public sealed class Loan(BookCopy copy, Member member, DateOnly borrowed)
{
public BookCopy Copy { get; } = copy;
public Member Member { get; } = member;
public DateOnly Borrowed { get; } = borrowed;
public DateOnly Due => Borrowed.AddDays(14);
public DateOnly? Returned { get; private set; }
public int OverdueDays(DateOnly today) => Math.Max(0, (Returned ?? today).DayNumber - Due.DayNumber);
public void Close(DateOnly date) => Returned = date;
}
public interface IFinePolicy { decimal Fine(Loan loan, DateOnly today); }
public sealed class PerDayFine(decimal perDay) : IFinePolicy { public decimal Fine(Loan l, DateOnly t) => l.OverdueDays(t) * perDay; }
public sealed class LibraryService(IFinePolicy fines, INotifier notifier)
{
private const int MaxLoans = 5;
public Loan Borrow(Member m, BookCopy c, DateOnly today)
{
if (m.Loans.Count(l => l.Returned is null) >= MaxLoans) throw new InvalidOperationException("Loan limit reached");
if (c.Status != CopyStatus.Available) throw new InvalidOperationException("Copy not available");
c.Status = CopyStatus.Loaned;
var loan = new Loan(c, m, today);
m.Loans.Add(loan);
return loan;
}
public decimal Return(Loan loan, DateOnly today)
{
loan.Close(today);
loan.Copy.Status = CopyStatus.Available;
notifier.NotifyNextReservation(loan.Copy.Book); // Observer-style hook for reservations
return fines.Fine(loan, today);
}
}
public interface INotifier { void NotifyNextReservation(Book book); }Tables: Books(Isbn PK), BookCopies(Barcode PK, Isbn FK, Status), Members, Loans(Id, Barcode FK, MemberId FK, Borrowed, Due, Returned), Reservations, Fines.