본문 바로가기

JAVA

[Java] Lv_3 도서관 프로젝트

요구사항

  • ⬜ 도서를 대여할 수 있어야 한다.
  • ⬜ 대여 중인 도서는 다시 대여할 수 없다.
  • ⬜ 반납 기능이 있어야 한다.

 

 


 

 

문제 풀이

Main

더보기
package lv_3;

import java.util.ArrayList;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Library library = new Library(new ArrayList<>());
        library.addBook(new Book("The Little Prince", "Antoine de Saint-Exupéry", 1943));
        library.addBook(new Book("Cinderella", "Charles Perrault", 1697));

        while(true) {
            showMenu();
            int input = Integer.parseInt(scanner.nextLine());

            switch (input) {
                case 0 -> {
                    System.out.println("프로그램을 종료합니다.");
                    return;
                }
                case 1 -> library.rentBook(scanner.nextLine());
                case 2 -> library.returnBook(scanner.nextLine());
                case 3 -> library.printBook(scanner.nextLine());
                case 4 -> library.printAllBook();
            }
        }
    }

    // 메뉴를 보여준다.
    public static void showMenu() {
        System.out.println("[ Library Menu ]");
        System.out.println("0. 종료");
        System.out.println("1. 도서 대여");
        System.out.println("2. 도서 반납");
        System.out.println("3. 도서 검색");
        System.out.println("4. 도서 목록 출력");
    }
}
  • Scanner 객체를 생성하여, 사용자로부터 입력을 받을 수 있게 하였습니다.
  • 반복적으로 보여지는 메뉴를 메서드화 하였습니다.
  • 입력에 따른 행동을 수행하도록 switch 문을 통해 나타내었습니다.

 

 

 

Library

더보기
package lv_3;

import java.util.List;
import java.util.Optional;

public class Library {
    private final List<Book> bookList;

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

    public void addBook(Book book) {
        bookList.add(book);
    }

    public Optional<Book> findBookByTitle(String title) {
        for(Book book : bookList) {
            if(book.getTitle().equalsIgnoreCase(title)) {
                return Optional.of(book);
            }
        }
        return Optional.empty();
    }

    public void printBook(String title) {
        Optional<Book> book = findBookByTitle(title);
        if (book.isPresent()) {
            Book foundBook = book.get();
            System.out.println(foundBook + "\n");
        } else {
            System.out.println(title + "은/는 존재하지 않는 책입니다.\n");
        }
    }

    public void printAllBook() {
        System.out.println("[ 전체 책 목록 ]");
        for(Book book : bookList) {
            System.out.println(book);
        }
        System.out.println();
    }

    public void rentBook(String title) {
        Optional<Book> book = findBookByTitle(title);
        if(book.isPresent()) {
            Book foundBook = book.get();

            if (foundBook.Rented()) {
                System.out.println(foundBook.getTitle() + " : 이미 대여된 책입니다.\n");
            } else {
                System.out.println(foundBook.getTitle() + " : 대여 완료\n");
                book.get().setRented(true);
            }
        } else {
            System.out.println(title + "은/는 존재하지 않는 책입니다.\n");
        }
    }

    public void returnBook(String title) {
        Optional<Book> book = findBookByTitle(title);
        if(book.isPresent()) {
            Book foundBook = book.get();

            if (foundBook.Rented()) {
                System.out.println(book.get().getTitle() + " : 반납 완료\n");
                book.get().setRented(false);
            } else {
                System.out.println(foundBook.getTitle() + " : 이미 반납된 책입니다.\n");
            }
        } else {
            System.out.println(title + "은/는 존재하지 않는 책입니다.\n");
        }
    }
}
  • 기존의 findAndPrintBookByTitle() 메서드를 findBookByTitle()과 printBook()으로 분리하였습니다.
  • rentBook()와 returnBook() 메서드를 통해 책 대여 상태를 변경해주었습니다. Optional를 사용하여, null에 대해서도 안전하게 처리해주었습니다.

 

 

 

Book

더보기
package lv_3;

public class Book {
    private String title;
    private String author;
    private int publishYear;
    private boolean isRented;

    public Book(String title, String author, int publishYear) {
        this.title = title;
        this.author = author;
        this.publishYear = publishYear;
    }

    public void setRented(boolean rent) {
        isRented = rent;
    }

    public boolean Rented() {
        return isRented;
    }

    public String getTitle() {
        return title;
    }

    @Override
    public String toString() {
        return String.format("제목 : %-20s | 저자 : %-30s | 출판 연도 : %-13s",title,author,publishYear);
    }
}

 

 


 

 

 

객체의 역할과 책임

Main Library Book
Scanner 객체 생성 책 추가 책의 정보 보관
Library 객체 생성 책 검색 자기 자신의 정보를 문자열로 표현
Book 객체 생성 책 대여 및 반납 로직 처리 책의 정보 제공
전체 흐름 처리 도서 출력  

 

 

 


 

 

실행 흐름

실행 흐름

 

 


 

 

GPT 분석

`Book` 클래스의 상태 변경 책임 강화

  • 현재 상태 변경은 외부에서 setRent(true)로 처리되고 있어, 객체의 자율성이 떨어집니다. 행동 메서드로 상태 변경을 위임하는 것이 객체지향적으로 더 좋습니다
    • 객체의 내부 상태를 외부에서 조작하게하면, 객체가 스스로 자신의 상태를 지키지 못하는 구조. 즉, 객체의 자율성이 떨어진다라고 표현합니다.
    • 내부 구조가 외부에 노출되어 캡슐화가 깨진다.
    • 변경을 하게 되면, 외부 코드를 다 고쳐야 한다.

중복 메시지 출력 개선

  • rentBook() / returnBook() 등에서 System.out.println()을 여러 번 쓰기보다는, 메시지 생성을 메서드로 분리할 수 있어요.
    또는 출력을 별도의 Printer 클래스에 위임하는 것도 SRP 측면에서 좋습니다 (Lv4에서 적용해볼 수 있음).

`Library` 클래스의 책임이 조금 과해짐

  • 책 추가, 책 검색, 책 대여 및 반납 로직 처리, 도서 상태 출력
  • 개선 제안 : 책의 상태는 Book이, 출력은 별도의 `Printer` 또는 `View` 객체가 담당하면 더 명확합니다.

 

 

'JAVA' 카테고리의 다른 글

[Java] Enum  (0) 2025.05.04
[Java] Lv_4 도서관 프로젝트  (0) 2025.05.02
[Java] Lv_2 도서관 프로젝트  (0) 2025.05.01
[Java] Lv_1 도서관 프로젝트  (0) 2025.05.01
[Java] 도전 과제 Lv_2 키오스크  (0) 2025.04.28