CodingNic

Object Oriented Programming

Mini Project: Library Management System

Object Oriented Programming 60 min read

Mini Project: Library Management System

Objectives

By the end of this chapter, you should be able to:

  • Design several classes that collaborate with each other, not just one class in isolation
  • Combine inheritance, custom exceptions, abc, and @property in a single working program

💡 Why this matters: The Deck of Cards exercise used two classes. A real program usually needs more than that, with classes that reference and act on each other. A library, its books, and its members are a natural next step up in complexity.

The Project

Build a Library Management System: a program that tracks a collection of items (books and, as a bonus, other media types), the members who can borrow them, and the borrowing and returning process itself, entirely in memory for now (file persistence comes in a later module).

Core Requirements

LibraryItem (abstract base class)

  • An ABC with title and is_checked_out (starting False)
  • An @abstractmethod called item_type() that subclasses must implement, returning a string like "Book"

Book (subclass of LibraryItem)

  • Adds author and isbn
  • Implements item_type() to return "Book"
  • A @property called display_title that returns something like "The Hobbit by J.R.R. Tolkien" combining title and author

Member

  • Has a name and a list of currently borrowed items
  • borrow(item): adds the item to the member’s list and marks it checked out
  • return_item(item): removes the item from the member’s list and marks it available again

Library

  • Holds a collection of LibraryItems and a collection of Members
  • add_item(item) / add_member(member)
  • checkout(member, item): has the member borrow the item, but raises a custom ItemUnavailableError if it’s already checked out
  • return_item(member, item): has the member return the item
  • find_by_title(title): returns the first matching item, or None

Custom Exception

  • ItemUnavailableError(Exception): raised by checkout() when an item is already checked out

Suggested Structure

python
from abc import ABC, abstractmethod

class ItemUnavailableError(Exception):
    pass


class LibraryItem(ABC):
    def __init__(self, title):
        self.title = title
        self.is_checked_out = False

    @abstractmethod
    def item_type(self):
        pass


class Book(LibraryItem):
    def __init__(self, title, author, isbn):
        super().__init__(title)
        self.author = author
        self.isbn = isbn

    def item_type(self):
        return "Book"

    @property
    def display_title(self):
        return f"{self.title} by {self.author}"


class Member:
    def __init__(self, name):
        self.name = name
        self.borrowed_items = []

    def borrow(self, item):
        item.is_checked_out = True
        self.borrowed_items.append(item)

    def return_item(self, item):
        item.is_checked_out = False
        self.borrowed_items.remove(item)


class Library:
    def __init__(self):
        self.items = []
        self.members = []

    def add_item(self, item):
        self.items.append(item)

    def add_member(self, member):
        self.members.append(member)

    def find_by_title(self, title):
        for item in self.items:
            if item.title == title:
                return item
        return None

    def checkout(self, member, item):
        if item.is_checked_out:
            raise ItemUnavailableError(f"{item.title} is already checked out")
        member.borrow(item)

    def return_item(self, member, item):
        member.return_item(item)

Fill in the pieces yourself rather than copying this directly: deciding which class is responsible for what is the real exercise here.

Bonus Extensions

  • Add a second LibraryItem subclass, like DVD or Magazine, with its own item_type(), and confirm your Library handles a mix of both without changes to its own code (that’s polymorphism, paying off).
  • Give Member a limit (say, three items at once) and raise a custom BorrowingLimitExceededError if they try to check out a fourth.
  • Add Library.overdue_items(), using Module 8’s datetime if you want to track due dates.

Try It

  1. Build LibraryItem, Book, Member, and Library, then add a few books and members, and check some books out.
  2. Try checking out an already-checked-out book, and confirm ItemUnavailableError is raised. Then catch it and print a friendly message instead of letting the program crash.
  3. Confirm LibraryItem() on its own raises TypeError, since it’s abstract.
  4. Attempt at least one bonus extension.

Recap

You’ve now designed a small system of collaborating classes (an abstract base class, a concrete subclass, and two more classes that reference and act on both of them), using nearly everything from this module at once. That’s a meaningfully different skill from writing one class in isolation, and it’s the shape most real object-oriented code actually takes.

Next module: reading from and writing to files.