This I have written as part of my LLD Practice. Please let me know further imporvements that can be done.
Also tell current design is Strong/Average/Lean Hire ?
/*
Similiar to car rental System
Flow->
Domain ===> Repository(DB) ==> Service (Buisness Logic) ==> Controller (Client Code)
======= Domain =======
Book
Search
PricingStrategy
FineStrategy
PaymentModule
Booking
======= Repository (DB Logic) =======
LibraryRepository
BookingRepository
======= Service (Buisness Logic) =======
SearchService
LibraryRentalService
======= Controller (Client Interaction) =======
LibraryRentalController (Client Interaction)
Client Code
*/import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
enum BookGenre{
Literature, Science, Fiction
}
enum BookStatus{
Available, Reserved
}
enum PaymentMode{
UPI, Cash
}
class User{
String id;
String name;
String email;
String phoneNo;
}
class Book{
String bookId;
String bookName;
String author;
BookStatus bookStatus;
BookGenre bookGenre;
}
interface PricingStrategy{
double calculatePrice(List<Book> books, LocalDateTime from, LocalDateTime to);
}
class FlatPricingStrategy implements PricingStrategy{
@Override
public double calculatePrice(List<Book> books, LocalDateTime from, LocalDateTime to){
// long days= ChronoUnit.DAYS.between(from,to);
long days= Duration.between(from,to).toDays();
return 100*days;
}
}
interface FineStrategy{
double calculateFine(LocalDateTime actualReturn, LocalDate currentDate);
}
class FlatFineStrategy implements FineStrategy{
@Override
public double calculateFine(LocalDateTime actualReturn, LocalDate currentDate){
long days= Duration.between(actualReturn,currentDate).toDays();
if(days<0) return 0.0;
return 100*days;
}
}
interface Payment{
void pay(double amount);
}
class UPIPayment implements Payment{
@Override
void pay(double amount){
}
}
class CashPayment implements Payment{
@Override
void pay(double amount){
}
}
class PaymentFactory{
static public Payment getPaymentMethod(PaymentMode mode){
switch(mode){
case UPI: return new UPIPayment();
case Cash: return new CashPayment();
default: throw new IllegalArgumentException("Invalid Method");
}
}
}
class Booking{
String id;
User user;
List<Book> books;
LocalDateTime from;
LocalDateTime to;
double amount;
PaymentMode paymentMode;
boolean isActive;
Booking(User user, List<Book> books, LocalDateTime from, LocalDateTime to, PaymentMode mode){
this.id= UUID.randomUUID().toString();
this.books=books;
this.from=from;
this.to=to;
this.paymentMode=mode;
this.isActive=true;
}
}
/* ====== Repository ====== */
class BookRepository{
Map<String,Book> booksDb=new HashMap<>();
synchronized boolean addBook(Book book){
booksDb.put(book.bookId, book);
return true;
}
List<Book> getAllBooks(){
return new ArrayList<>(booksDb.values());
}
synchronized boolean isAvailable(String bookId){
return booksDb.get(bookId).bookStatus==BookStatus.Available;
}
synchronized boolean reserveBooks(List<Book> books){
for(Book book:books){
Book bookToReserve=booksDb.get(book.bookId);
bookToReserve.bookStatus=BookStatus.Reserved;
booksDb.put(bookToReserve.bookId, bookToReserve);
}
return true;
}
synchronized boolean markAvailableBooks(List<Book> books){
for(Book book:books){
Book bookToReserve=booksDb.get(book.bookId);
bookToReserve.bookStatus=BookStatus.Available;
booksDb.put(bookToReserve.bookId, bookToReserve);
}
return true;
}
}
class BookingRepository{
Map<String,Booking> bookingDb;
boolean addBooking(Booking booking){
bookingDb.put(booking.id, booking);
return true;
}
Booking getBooking(String bookingId){
return bookingDb.get(bookingId);
}
boolean removeBooking(String bookingId){
bookingDb.remove(bookingId);
return true;
}
}
/* ====== Service ====== */
class SearchService{
BookRepository bookRepository;
List<Book> searchByName(String name){
List<Book> list=new ArrayList<>();
for(Book book:bookRepository.getAllBooks()){
if(book.bookName.equals(name)){
list.add(book);
}
}
return list;
}
List<Book> searchByAuthor(String author){
List<Book> list=new ArrayList<>();
for(Book book:bookRepository.getAllBooks()){
if(book.author.equals(author)){
list.add(book);
}
}
return list;
}
List<Book> searchByBookGenre(BookGenre bookGenre){
List<Book> list=new ArrayList<>();
for(Book book:bookRepository.getAllBooks()){
if(book.bookGenre==bookGenre){
list.add(book);
}
}
return list;
}
}
class LibraryService{
BookRepository bookRepository;
BookingRepository bookingRepository;
PricingStrategy pricingStrategy;
FineStrategy fineStrategy;
synchronized Booking issueBook(User user, List<Book> books, LocalDateTime from, LocalDateTime to, PaymentMode paymentMode){
List<Book> toIssue=new ArrayList<>();
for(Book book:books){
if(book.bookStatus==BookStatus.Available) toIssue.add(book);
}
bookRepository.reserveBooks(toIssue);
double amount=pricingStrategy.calculatePrice(toIssue, from, to);
Payment payment=PaymentFactory.getPaymentMethod(paymentMode);
payment.pay(amount);
Booking booking=new Booking(user,toIssue,from,to,paymentMode);
bookingRepository.addBooking(booking);
return booking;
}
synchronized boolean cancelBooking(String bookingId){
Booking booking=bookingRepository.getBooking(bookingId);
if(booking==null){
throw new RuntimeException("Invalid id");
}
bookRepository.markAvailableBooks(booking.books);
bookingRepository.removeBooking(bookingId);
booking.isActive=false;
return true;
}
synchronized boolean returnBook(String bookingId){
Booking booking=bookingRepository.getBooking(bookingId);
if(booking==null){
throw new RuntimeException("Invalid id");
return false;
}
double fine=fineStrategy.calculateFine(booking.to,LocalDateTime.now());
if(fine>0){
Payment payment=PaymentFactory.getPaymentMethod(booking.paymentMode); //payment mode??????
payment.pay(fine);
}
bookRepository.markAvailableBooks(booking.books);
booking.isActive=false;
return true;
}
}
/* ====== Controller ====== */
class LibraryController{
LibraryService libraryService;
SearchService searchService;
synchronized Booking issueBook(User user, List<Book> books, LocalDateTime from, LocalDateTime to, PaymentMode paymentMode){
return libraryService.issueBook(user, books, from, to, paymentMode);
}
synchronized boolean cancelBooking(String bookingId){
return libraryService.cancelBooking(bookingId);
}
synchronized boolean returnBook(String bookingId){
return libraryService.returnBook(bookingId);
}
List<Book> searchByName(String name){
return searchService.searchByName(name);
}
List<Book> searchByAuthor(String author){
return searchService.searchByAuthor(author);
}
List<Book> searchByBookGenre(BookGenre bookGenre){
return searchService.searchByBookGenre(bookGenre);
}
}
public class Library {
public static void main(String[] args) {
User user=new User();
LibraryController controller=new LibraryController();
List<Book> books=controller.searchByAuthor("RD Sharma");
Booking booking=controller.issueBook(user,new ArrayList<>((Collection) books.get(0)),LocalDateTime.now(),LocalDateTime.of(2025,9,12,13,30),PaymentMode.Cash);
controller.returnBook(booking.id);
}
}