Developing a Library Management System using Java and OOP Principles

Architecting the System

To build a functional library management system in Java, we need to organize our code in to distinct modules: data models for books, user hierarchies for different access levels, and a decoupled set of operations. This approach leverages Object-Oriented Programming (OOP) concepts like inheritance, polymorphism, and encapsulation.

Core Data Models

The foundation of the system consists of the Book class, which represents individual titles, and the LibraryShelf class, which manages the clolection.

The Book Class

This entity encapsulates the properties of a book, including its title, author, price, category, and availability status.

public class Book {
    private String title;
    private String author;
    private double price;
    private String category;
    private boolean isLoaned;

    public Book(String title, String author, double price, String category) {
        this.title = title;
        this.author = author;
        this.price = price;
        this.category = category;
        this.isLoaned = false;
    }

    // Getters and Setters
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public String getAuthor() { return author; }
    public double getPrice() { return price; }
    public boolean isLoaned() { return isLoaned; }
    public void setLoaned(boolean loaned) { isLoaned = loaned; }

    @Override
    public String toString() {
        return String.format("Title: %-15s | Author: %-10s | Price: %-5.2f | Type: %-10s | Status: %s",
                title, author, price, category, (isLoaned ? "Borrowed" : "Available"));
    }
}

The LibraryShelf Class

The LibraryShelf acts as a container for our book objects, providing methods to access specific slots and track the total count.

public class LibraryShelf {
    private Book[] inventory = new Book[20];
    private int currentBookCount;

    public LibraryShelf() {
        inventory[0] = new Book("Java Basics", "John Smith", 45.0, "Tech");
        inventory[1] = new Book("Clean Code", "Robert Martin", 55.0, "Tech");
        inventory[2] = new Book("The Hobbit", "Tolkien", 30.0, "Fiction");
        this.currentBookCount = 3;
    }

    public Book getBookInstance(int index) {
        return inventory[index];
    }

    public void updateBook(int index, Book book) {
        inventory[index] = book;
    }

    public int getCurrentBookCount() {
        return currentBookCount;
    }

    public void setCurrentBookCount(int count) {
        this.currentBookCount = count;
    }

    public int getCapacity() {
        return inventory.length;
    }
}

User Management and Inheritance

The system distinguishes between administrative users and regular patrons. We use an abstract LibraryUser class to define common traits.

Abstract User Definition

public abstract class LibraryUser {
    protected String username;
    protected IAction[] actions;

    public LibraryUser(String username) {
        this.username = username;
    }

    public abstract int displayMenu();

    public void executeAction(int choice, LibraryShelf shelf) {
        if (choice >= 0 && choice < actions.length) {
            actions[choice].perform(shelf);
        } else {
            System.out.println("Invalid option.");
        }
    }
}

Admin and Regular User Implementations

Each user type initializes its own set of available operations in its constructor.

public class Administrator extends LibraryUser {
    public Administrator(String username) {
        super(username);
        this.actions = new IAction[]{
            new ShutdownAction(),
            new SearchAction(),
            new InsertAction(),
            new RemoveAction(),
            new ListAllAction()
        };
    }

    @Override
    public int displayMenu() {
        System.out.println("--- Admin Console: " + this.username + " ---");
        System.out.println("1. Find Book | 2. Add Book | 3. Delete Book | 4. Show All | 0. Exit");
        return new java.util.Scanner(System.in).nextInt();
    }
}

public class RegularMember extends LibraryUser {
    public RegularMember(String username) {
        super(username);
        this.actions = new IAction[]{
            new ShutdownAction(),
            new SearchAction(),
            new LoanAction(),
            new ReturnAction()
        };
    }

    @Override
    public int displayMenu() {
        System.out.println("--- Member Portal: " + this.username + " ---");
        System.out.println("1. Find Book | 2. Borrow | 3. Return | 0. Exit");
        return new java.util.Scanner(System.in).nextInt();
    }
}

Functional Operations

By using an interface, we can treat every library action (adding, deleting, etc.) as a polymorphic object.

The Action Interface

public interface IAction {
    void perform(LibraryShelf shelf);
}

Implementing the Add Operation

public class InsertAction implements IAction {
    @Override
    public void perform(LibraryShelf shelf) {
        if (shelf.getCurrentBookCount() == shelf.getCapacity()) {
            System.out.println("Shelf is full!");
            return;
        }

        java.util.Scanner input = new java.util.Scanner(System.in);
        System.out.print("Enter Title: ");
        String t = input.nextLine();
        System.out.print("Enter Author: ");
        String a = input.nextLine();
        System.out.print("Enter Price: ");
        double p = input.nextDouble();
        input.nextLine(); // consume newline
        System.out.print("Enter Category: ");
        String c = input.nextLine();

        Book newBook = new Book(t, a, p, c);
        int pos = shelf.getCurrentBookCount();
        shelf.updateBook(pos, newBook);
        shelf.setCurrentBookCount(pos + 1);
        System.out.println("Book added successfully.");
    }
}

Implementing the Loan Operation

public class LoanAction implements IAction {
    @Override
    public void perform(LibraryShelf shelf) {
        System.out.print("Enter the title of the book to borrow: ");
        String target = new java.util.Scanner(System.in).nextLine();

        for (int i = 0; i < shelf.getCurrentBookCount(); i++) {
            Book b = shelf.getBookInstance(i);
            if (b.getTitle().equalsIgnoreCase(target)) {
                if (b.isLoaned()) {
                    System.out.println("This book is already out on loan.");
                    return;
                }
                b.setLoaned(true);
                System.out.println("Loan processed successfully.");
                return;
            }
        }
        System.out.println("Book not found.");
    }
}

The Main Controller

The entry point manages the login process and runs the main execution loop, passing the user's menu choice to the execution engine.

public class SystemApp {
    public static LibraryUser authenticate() {
        java.util.Scanner scanner = new java.util.Scanner(System.in);
        System.out.print("Enter Name: ");
        String name = scanner.nextLine();
        System.out.println("Select Identity: 1. Admin | 2. Member");
        int role = scanner.nextInt();

        return (role == 1) ? new Administrator(name) : new RegularMember(name);
    }

    public static void main(String[] args) {
        LibraryShelf myShelf = new LibraryShelf();
        LibraryUser activeUser = authenticate();

        while (true) {
            int command = activeUser.displayMenu();
            activeUser.executeAction(command, myShelf);
        }
    }
}

Tags: java Object-Oriented Programming Software Design Library Management System Polymorphism

Posted on Sat, 29 Aug 2026 16:22:49 +0000 by pastijalan