Skip to main content

Design a Library Management System

Problem Statement

Design a library management system that allows users to search, borrow, and return books. The design should manage book availability, maintain borrower records, and ensure that a book cannot be issued to multiple users at the same time.


Functional Requirements

  • The design should support adding multiple books to the library
  • Users should be able to search books using title or author
  • A user should be able to borrow a book if it is available
  • A borrowed book should not be issued to another user
  • Users should be able to return borrowed books
  • Returned books should become available again
  • The design should maintain borrowing records
  • The system should track issued and available books

Objects Required

  • Book
  • Member
  • BorrowRecord
  • Library
  • LibraryManagementSystem
  • BookStatus

BookStatus Enum


public enum BookStatus {
    AVAILABLE,
    ISSUED
}

The BookStatus enum represents the current state of a book.

Using enums prevents invalid status values and keeps the state transitions easy to manage.


Book Class

The Book class represents a single book inside the library.


public class Book {

    private String bookId;
    private String title;
    private String author;
    private BookStatus status;

    public Book(String bookId,
                String title,
                String author) {

        this.bookId = bookId;
        this.title = title;
        this.author = author;
        this.status = BookStatus.AVAILABLE;
    }

    public boolean isAvailable() {
        return status == BookStatus.AVAILABLE;
    }

    public void issueBook() {
        status = BookStatus.ISSUED;
    }

    public void returnBook() {
        status = BookStatus.AVAILABLE;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }
}

The constructor initializes the book with its id, title, and author.

Every newly added book starts with the AVAILABLE status.

The isAvailable() method checks whether the book can currently be borrowed.

The issueBook() method updates the status when a member borrows the book.

The returnBook() method marks the book as available again after return.

The getter methods are used during searching and displaying book details.


Member Class

The Member class stores information related to a library user.


public class Member {

    private String memberId;
    private String name;

    public Member(String memberId,
                  String name) {

        this.memberId = memberId;
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

The constructor initializes member details.

The getName() method is useful while displaying borrowing information.


BorrowRecord Class

The BorrowRecord class maintains borrowing details for issued books.


import java.time.LocalDate;

public class BorrowRecord {

    private String recordId;
    private Member member;
    private Book book;
    private LocalDate issueDate;

    public BorrowRecord(String recordId,
                        Member member,
                        Book book) {

        this.recordId = recordId;
        this.member = member;
        this.book = book;
        this.issueDate = LocalDate.now();
    }

    public void closeRecord() {
        book.returnBook();
    }
}

The constructor creates a borrowing record and stores the issue date.

The closeRecord() method is called when the member returns the book.

Inside this method, the associated book is marked as available again.


Library Class

The Library class manages all books available in the library.


import java.util.*;

public class Library {

    private List<Book> books;

    public Library(List<Book> books) {
        this.books = books;
    }

    public List<Book> searchByTitle(
            String title) {

        List<Book> result =
                new ArrayList<>();

        for (Book book : books) {

            if (book.getTitle()
                    .equalsIgnoreCase(title)) {

                result.add(book);
            }
        }

        return result;
    }

    public List<Book> searchByAuthor(
            String author) {

        List<Book> result =
                new ArrayList<>();

        for (Book book : books) {

            if (book.getAuthor()
                    .equalsIgnoreCase(author)) {

                result.add(book);
            }
        }

        return result;
    }
}

The constructor initializes the library with all available books.

The searchByTitle() method iterates through all books and returns matching titles.

The searchByAuthor() method searches books written by a specific author.

Keeping search logic inside the library class avoids pushing collection related operations to higher level classes.


LibraryManagementSystem Class

The LibraryManagementSystem class coordinates borrowing and returning operations.


import java.util.*;

public class LibraryManagementSystem {

    private Library library;

    public LibraryManagementSystem(
            Library library) {

        this.library = library;
    }

    public BorrowRecord borrowBook(
            Member member,
            Book book) {

        if (!book.isAvailable()) {

            System.out.println(
                    "Book is already issued"
            );

            return null;
        }

        book.issueBook();

        return new BorrowRecord(
                UUID.randomUUID().toString(),
                member,
                book
        );
    }

    public void returnBook(
            BorrowRecord record) {

        record.closeRecord();

        System.out.println(
                "Book returned successfully"
        );
    }
}

The constructor initializes the management system with the library object.

The borrowBook() method first checks whether the requested book is available.

If the book is already issued, the borrowing request is rejected immediately.

If the book is available, its status is updated and a borrowing record is created.

The returnBook() method closes the borrow record and marks the book as available again.


Main Class

The Main class demonstrates the complete library borrowing flow.


import java.util.*;

public class Main {

    public static void main(String[] args) {

        Book book1 = new Book(
                "B1",
                "Clean Code",
                "Robert Martin"
        );

        Book book2 = new Book(
                "B2",
                "Design Patterns",
                "GoF"
        );

        Library library =
                new Library(
                        Arrays.asList(book1, book2)
                );

        LibraryManagementSystem system =
                new LibraryManagementSystem(
                        library
                );

        Member member =
                new Member(
                        "M1",
                        "Prasanna"
                );

        BorrowRecord record =
                system.borrowBook(
                        member,
                        book1
                );

        if (record != null) {

            System.out.println(
                    "Book issued successfully"
            );
        }

        system.returnBook(record);
    }
}

The main() method starts by creating books and adding them to the library.

A member then borrows one of the available books.

Once the borrowing operation succeeds, the book status changes to issued.

Finally, the book is returned, making it available again for future borrowing.


Class Diagram

BookStatusAVAILABLEISSUEDBookbookId : Stringtitle : Stringauthor : Stringstatus : BookStatusisAvailable() : booleanissueBook() : voidreturnBook() : voidgetTitle() : StringgetAuthor() : StringMembermemberId : Stringname : StringgetName() : StringBorrowRecordrecordId : Stringmember : Memberbook : BookissueDate : LocalDatecloseRecord() : voidLibrarybooks : List<Book>searchByTitle(title : String) : List<Book>searchByAuthor(author : String) : List<Book>LibraryManagementSystemlibrary : Library member : Member,book : Book record : BorrowRecordborrowBook() : BorrowRecord returnBook() : voidMainmain(args : String[]) : void

Also See

Comments

Popular posts from this blog

Designing a Parking Lot - Low Level Design

Problem Statement Design a parking lot that can handle vehicles entering and leaving while managing parking across multiple floors. Each vehicle should be assigned a suitable parking spot based on its type, and the spot should be freed once the vehicle exits. The design should also support generating a ticket at entry and optionally calculating the parking fee based on the duration of stay. Asked In Companies Amazon Google Microsoft Uber Walmart Flipkart Meta PayPal Oracle Salesforce Adobe Apple Intuit LinkedIn Atlassian Functional Requirements The design should support multiple vehicle types such as bikes, cars, and trucks A vehicle must be assigned a parking spot compatible with its type A parking spot cannot be assigned to more than one vehicle at a time The parking lot should support multiple levels (floors) The design should search and allocate an availa...

Most Frequently Asked Low Level Design(LLD) Interview Questions

Below are the curated list of most commonly asked Low Level Design (LLD) interview problems. Each problem includes a short description and a link to the complete solution with code and class diagrams. Design Parking Lot System The system should handle parking for different vehicle types such as bikes, cars, and trucks. It should manage slot allocation, availability tracking, and entry/exit flow. The design also ensures efficient usage of parking space under varying load conditions. View Solution Design Elevator / Lift System The system should support multiple elevators operating across floors with request handling logic. It focuses on scheduling algorithms to minimize wait time and optimize movement. It also manages direction control and concurrent floor requests. View Solution Design Movie Ticket Booking System The system should allow users to browse movies, select shows, and book seats. It handles seat ...

Software Design Patterns for LLD Interviews: A Complete Guide

Software Design Patterns for LLD Interviews: A Complete Guide In Software Development Engineer (SDE) interviews—especially for mid-level and senior roles—low-level design (LLD) rounds assess your ability to write clean, reusable, maintainable, and extensible code. The foundation of resolving these architectural challenges lies in the standard Gang of Four (GoF) Design Patterns. Rather than memorizing theoretical definitions, interviewers expect you to apply these patterns to real-world scenarios, identifying the trade-offs of each. Below is a comprehensive guide to the 12 most frequently asked design patterns in LLD interviews, categorized by their classification (Creational, Structural, and Behavioral). Each pattern contains a concrete, real-world Java implementation and a detailed breakdown of design decisions. Creational Design Patterns Creational design patterns deal with object creation mechanisms. They abstract the instantiation process, making a system independent of how...