Borrowing System Logic
Part of the Object Oriented Programming section of Coddy's C# journey — lesson 64 of 70.
Challenge
EasyLet's bring your Library System to life by implementing the core borrowing logic! You'll create a centralized system that coordinates between books and users, enforcing library rules like borrowing limits and ensuring books can only be borrowed when available.
You'll continue building on your existing four-file structure:
Book.cs: Keep your Book class withId,Title,Author, andIsAvailableproperties, along with theBorrow()andReturn()methods from the previous lesson.User.cs: Keep your User class withName,MemberId,BorrowedCount, and the methods for managing borrowed books. Add a constantMaxBooksset to 3 that represents the maximum number of books a user can borrow at once. Add a methodCanBorrow()that returns true only if the user has borrowed fewer thanMaxBooks.Library.cs: This is where your borrowing system logic comes together. Your Library class should have collections of books and users, plus methods to add them. Implement two key methods:BorrowBook(string bookId, int memberId)- Coordinates the borrowing process. It should check if the book exists, if the user exists, if the book is available, and if the user can borrow more books. Return appropriate messages for each failure case or success.ReturnBook(string bookId, int memberId)- Handles returns by verifying the user actually has the book before processing the return.
Program.cs: Process library operations and display results.
Your BorrowBook method should return these messages based on the situation:
Book not found- when the book ID doesn't existUser not found- when the member ID doesn't exist{Title} is not available- when the book is already borrowed{Name} has reached the borrowing limit- when the user already has 3 books{Name} borrowed {Title}- on successful borrow
Your ReturnBook method should return:
Book not foundorUser not found- for invalid IDs{Name} did not borrow {Title}- when the user tries to return a book they don't have{Name} returned {Title}- on successful return
You will receive the following inputs:
- Library name
- Number of books, then each book as
id|title|author - Number of users, then each user as
name|memberId - Number of operations, then each operation as
action|bookId|memberId
Print the result of each operation on its own line.
For example, if the inputs are:
Central Library
4
B001|The Hobbit|Tolkien
B002|1984|Orwell
B003|Dune|Herbert
B004|Foundation|Asimov
2
Alice|101
Bob|102
6
borrow|B001|101
borrow|B002|101
borrow|B003|101
borrow|B004|101
borrow|B001|102
return|B002|101The output should be:
Alice borrowed The Hobbit
Alice borrowed 1984
Alice borrowed Dune
Alice has reached the borrowing limit
The Hobbit is not available
Alice returned 1984Notice how the Library class acts as the coordinator - it validates all conditions before allowing operations, keeping your Book and User classes focused on their own responsibilities. This separation makes your code easier to maintain and test!
Try it yourself
using System;
using System.Collections.Generic;
namespace LibrarySystem
{
class Program
{
public static void Main(string[] args)
{
// Read library name
string libraryName = Console.ReadLine();
// Create a Library instance with the library name
Library library = new Library(libraryName);
// Read number of books
int numBooks = Convert.ToInt32(Console.ReadLine());
// Read and add books
for (int i = 0; i < numBooks; i++)
{
string bookInput = Console.ReadLine();
string[] bookParts = bookInput.Split('|');
string bookId = bookParts[0];
string bookTitle = bookParts[1];
string bookAuthor = bookParts[2];
Book book = new Book(bookId, bookTitle, bookAuthor);
library.AddBook(book);
}
// Read number of users
int numUsers = Convert.ToInt32(Console.ReadLine());
// Read and register users
for (int i = 0; i < numUsers; i++)
{
string userInput = Console.ReadLine();
string[] userParts = userInput.Split('|');
string userName = userParts[0];
int memberId = Convert.ToInt32(userParts[1]);
User user = new User(userName, memberId);
library.RegisterUser(user);
}
// Read number of operations
int numOperations = Convert.ToInt32(Console.ReadLine());
// Process operations
for (int i = 0; i < numOperations; i++)
{
string operationInput = Console.ReadLine();
string[] opParts = operationInput.Split('|');
string action = opParts[0];
string bookId = opParts[1];
int memberId = Convert.ToInt32(opParts[2]);
if (action == "borrow")
{
string result = library.BorrowBook(bookId, memberId);
Console.WriteLine(result);
}
else if (action == "return")
{
string result = library.ReturnBook(bookId, memberId);
Console.WriteLine(result);
}
}
}
}
}
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesNamespaces & DirectivesIntro to Classes & ObjectsThe 'this' KeywordMethods and ParametersFields vs PropertiesConstructorsObject InitializersRecap - Simple Calculator4Inheritance
Basic Inheritance (:) SyntaxThe 'base' KeywordVirtual & Override KeywordsSealed ClassesThe 'object' Base ClassRecap - Employee Hierarchy7Advanced Features
Operator OverloadingIndexers (this[])ToString() OverrideExtension MethodsRecap - Custom List2Properties & Static Members
Auto-Implemented PropertiesRead/Write-Only PropertiesStatic Fields & MethodsStatic ClassesExpression-Bodied Members5Polymorphism & Interfaces
Compile vs Runtime PolyInterface vs Abstract ClassMultiple InterfacesExplicit InterfacesUpcasting & DowncastingRecap - Shape Calculator3Class Architecture
Instance vs Static Data'readonly' & 'const' KeywordsBacking FieldsRecap - Bank Account Manager6Encapsulation
Access ModifiersProperties for EncapsulationData Hiding ImplementationImmutability PatternsRecap - Student Records12Project: Library System
Project StructureBook and User Models