Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • About
  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

👥10,105visitors

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
HomeLearnSystem DesignLow-Level Design & Design PatternsMachine Coding Exercises
✓ FreeBeginner· 7 min read

Library Management System

Core classes for a library system, reservation queueing when a book is checked out, and fine calculation as a pluggable strategy.

Published September 23, 2026


Library Management System

Core classes

class Book {
    private final String isbn;
    private final String title;
    private BookStatus status = BookStatus.AVAILABLE; // AVAILABLE, CHECKED_OUT, RESERVED
}

class Member {
    private final String memberId;
    private final List<Loan> activeLoans = new ArrayList<>();
}

class Loan {
    private final Book book;
    private final Member member;
    private final Instant checkoutDate;
    private final Instant dueDate;
    private Instant returnDate; // null until returned
}

class Library {
    private final Map<String, Book> catalog;
    private final Map<String, Queue<Member>> reservationQueues = new HashMap<>(); // per book ISBN
}

Loan is a deliberate separate class rather than a field on Book — a book can have many loans over its lifetime, and keeping loan history (not just current status) requires a record per checkout, not a single mutable field.

Advertisement

Reservation queueing

class Library {
    Optional<Book> checkout(String isbn, Member member) {
        Book book = catalog.get(isbn);
        if (book.getStatus() != BookStatus.AVAILABLE) return Optional.empty();
        book.setStatus(BookStatus.CHECKED_OUT);
        loans.add(new Loan(book, member, Instant.now(), Instant.now().plus(Duration.ofDays(14))));
        return Optional.of(book);
    }

    void reserve(String isbn, Member member) {
        reservationQueues.computeIfAbsent(isbn, k -> new LinkedList<>()).add(member); // FIFO — first reservation, first served
    }

    void returnBook(String isbn) {
        Book book = catalog.get(isbn);
        Queue<Member> queue = reservationQueues.get(isbn);
        if (queue != null && !queue.isEmpty()) {
            Member next = queue.poll();
            book.setStatus(BookStatus.RESERVED); // held for the next member in line, not immediately AVAILABLE
            notifyMemberBookReady(next, book);
        } else {
            book.setStatus(BookStatus.AVAILABLE);
        }
    }
}

The RESERVED status (distinct from AVAILABLE) matters: a returned book with a waiting reservation queue shouldn't be checkoutable by a walk-in member ahead of whoever reserved it first — this is the detail that separates a design that merely tracks availability from one that correctly models fairness.

Fine calculation as a pluggable strategy

interface FineStrategy { double calculateFine(Loan loan); }

class StandardFineStrategy implements FineStrategy {
    private static final double DAILY_RATE = 0.25;
    public double calculateFine(Loan loan) {
        long overdueDays = Math.max(0, Duration.between(loan.getDueDate(), Instant.now()).toDays());
        return overdueDays * DAILY_RATE;
    }
}

class CappedFineStrategy implements FineStrategy {
    private final FineStrategy delegate;
    private final double cap;
    public double calculateFine(Loan loan) { return Math.min(delegate.calculateFine(loan), cap); } // Decorator over a Strategy
}

Same Strategy Pattern separation used throughout this course: fine policy can differ per library branch or member type without Library's checkout/return logic ever changing. CappedFineStrategy wrapping another FineStrategy is worth noticing — it's Decorator applied to a Strategy object, showing the two patterns aren't mutually exclusive.

Separating titles from physical copies

The core classes treat Book as a single object with a status. Real libraries own several copies of popular titles, and that one change reshapes the model:

class Title {                       // what a member searches for and reserves
    final String isbn; final String name; final List<String> authors;
    Title(String isbn, String name, List<String> authors) { this.isbn = isbn; this.name = name; this.authors = authors; }
}

enum CopyStatus { AVAILABLE, ON_LOAN, ON_HOLD_SHELF, LOST, UNDER_REPAIR }

class BookCopy {                    // what is physically lent out
    final String barcode; final Title title;
    CopyStatus status = CopyStatus.AVAILABLE;
    BookCopy(String barcode, Title title) { this.barcode = barcode; this.title = title; }
}
  • Reservations belong to the Title: a member wants any copy of the book, not copy #3.
  • Loans belong to a BookCopy: the library needs to know exactly which physical item is overdue or lost.
  • Availability is "does any copy of this title have status AVAILABLE?", which is a query, not a stored flag.

Checkout, return and the reservation hand-off

The interesting logic is on return: if someone is waiting for the title, the copy goes to the hold shelf for them instead of back on the open shelf.

class LibraryService {
    private final Map<String, List<BookCopy>> copiesByIsbn;
    private final Map<String, Deque<Reservation>> queueByIsbn = new HashMap<>();
    private final LoanPolicy policy;                 // limits and loan period, by member type
    private final Clock clock;

    LibraryService(Map<String, List<BookCopy>> copiesByIsbn, LoanPolicy policy, Clock clock) {
        this.copiesByIsbn = copiesByIsbn; this.policy = policy; this.clock = clock;
    }

    synchronized Loan checkout(Member member, String isbn) {
        if (member.activeLoans().size() >= policy.maxLoans(member))
            throw new LoanLimitExceededException(member.id());
        if (member.hasUnpaidFinesAbove(policy.fineBlockThreshold()))
            throw new MemberBlockedException(member.id());

        BookCopy copy = heldFor(member, isbn)                          // their reserved copy, if any
                .or(() -> firstWithStatus(isbn, CopyStatus.AVAILABLE))
                .orElseThrow(() -> new NoCopyAvailableException(isbn));

        copy.status = CopyStatus.ON_LOAN;
        Instant now = clock.instant();
        Loan loan = new Loan(copy, member, now, now.plus(policy.loanPeriod(member)));
        member.activeLoans().add(loan);
        return loan;
    }

    synchronized Fine returnCopy(Loan loan) {
        loan.markReturned(clock.instant());
        loan.member().activeLoans().remove(loan);
        Fine fine = policy.fineFor(loan);                              // FineStrategy from above

        Deque<Reservation> queue = queueByIsbn.getOrDefault(loan.copy().title.isbn, new ArrayDeque<>());
        Reservation next = queue.pollFirst();
        if (next != null) {
            loan.copy().status = CopyStatus.ON_HOLD_SHELF;
            next.assign(loan.copy(), clock.instant().plus(Duration.ofDays(3)));   // pickup deadline
            notifier.bookReady(next.member(), loan.copy().title);
        } else {
            loan.copy().status = CopyStatus.AVAILABLE;
        }
        return fine;
    }
}

Points worth making in an interview:

  • Business rules live in a LoanPolicy (max loans, loan period, blocking thresholds), which can differ for students, staff and premium members. They don't belong in if statements scattered through the service.
  • Returning is where the reservation queue advances. It's a state transition on the copy (ON_LOAN → ON_HOLD_SHELF), not only on the member.
  • Pickup deadlines: a scheduled job expires uncollected holds, and passes the copy to the next person in the queue, or back to AVAILABLE.
  • The Clock injection again makes due dates, fines and deadlines testable without waiting.

Search

Members search by title, author, subject or ISBN. At machine-coding scale, keep simple in-memory indexes (Map<String, Set<Title>> from each lower-cased author name or title word). At larger scale, delegate to a search engine. The CatalogSearch interface stays the same either way.

Follow-up questions this topic invites — and their answers

Q: What happens if a member never picks up a RESERVED book? A: A real system needs a timeout — after N days in RESERVED status unclaimed, the book reverts to AVAILABLE (or offers to the next person in the reservation queue), which would be implemented as a scheduled check rather than something triggered by a user action.

Q: Why is reservationQueues keyed by ISBN rather than by a specific physical book copy? A: This design assumes reservations are for a title, not a specific physical copy — if a library has multiple copies of the same ISBN, any returned copy can satisfy the next reservation, which is the more realistic and more useful behavior than binding a reservation to one specific physical book.

Q: How would you extend this to support multiple copies of the same book? A: Separate the concept of a Book (the title/metadata) from a BookCopy (one physical, individually trackable instance with its own status) — Book would hold a List<BookCopy>, and checkout logic would search for any AVAILABLE copy rather than checking a single book's status directly.

Q: Why model Title and BookCopy separately? A: They answer different questions. Members search for and reserve a title, while loans, damage and loss happen to specific physical copies. Merging them makes multiple copies, per-copy history and "any copy available" logic awkward.

Q: Where should rules like "students can borrow 3 books for 14 days" live? A: In a policy object selected by member type (Strategy), not hard-coded in the checkout method. Rules change more often than the checkout flow does, and policies can be tested and configured on their own.

Q: How do you stop two librarians checking out the last copy to two members at once? A: Make the status change atomic: synchronize within a single process, or use a conditional update (UPDATE copy SET status='ON_LOAN' WHERE barcode=? AND status='AVAILABLE') in a database, and treat 0 updated rows as "no longer available".

Advertisement

Previous

Elevator System — Implementation & Scheduling

Next

Tic-Tac-Toe / Board Game Design

AI Tutor

Lesson: Library Management System

Quick actions

AI responses can be inaccurate. Verify critical information.