JAVA
[Java] Lv_4 도서관 프로젝트
kimyongjun0129
2025. 5. 2. 23:38
요구사항
- ⬜ 사용자는 도서를 대여하고 반납할 수 있다.
- ⬜ 사용자별로 어떤 책을 대여했는지 확인할 수 있어야 한다.
- ⬜ 사용자 이름과 ID를 가진다.
문제 풀이
Main
더보기
package lv_4;
import java.util.ArrayList;
import java.util.Optional;
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<>(), new RentService());
library.addBook(new Book("The Little Prince", "Antoine de Saint-Exupéry", 1943));
library.addBook(new Book("Cinderella", "Charles Perrault", 1697));
while(true) {
User user = login();
showMenu();
int input = Integer.parseInt(scanner.nextLine());
switch (input) {
case 0 -> {
System.out.println("프로그램을 종료합니다.");
return;
}
case 1 -> {
String title = scanner.nextLine();
Optional<Book> book = library.findBookByTitle(title);
if (book.isPresent()) {
Book foundBook = book.get();
library.getRentService().rentBook(foundBook);
foundBook.setUserId(user.getId());
} else {
System.out.println(title + " : 책이 존재하지 않습니다.");
}
}
case 2 -> {
String title = scanner.nextLine();
Optional<Book> book = library.findBookByTitle(title);
if (book.isPresent()) {
Book foundBook = book.get();
if (foundBook.getUserId() == user.getId()) {
library.getRentService().returnBook(foundBook);
foundBook.resetUserId();
} else {
System.out.println(foundBook.getTitle() + " : 대여하지 않았습니다.");
}
}
}
case 3 -> library.printBook(scanner.nextLine());
case 4 -> library.printAllBook();
}
}
}
// 유저 정보 등록
public static User login() {
Scanner scanner = new Scanner(System.in);
System.out.println("[ 회원 정보 등록 ]");
System.out.print("ID : ");
int id = Integer.parseInt(scanner.nextLine());
return new User(id);
}
// 메뉴를 보여준다.
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. 도서 목록 출력");
}
}
- 책을 대출할 때, 유저의 ID를 넣어줍니다.
- 책을 반납할 때, 책에 넣어진 ID와 현재 유저의 ID가 동일하면, 반납이되도록하였다. 책이 반납되면, 책에있는 유저의 ID를 초기화해줍니다.
Library
더보기
package lv_4;
import java.util.List;
import java.util.Optional;
public class Library {
private final List<Book> bookList;
private final RentService rentService;
public Library(List<Book> bookList, RentService rentService) {
this.bookList = bookList;
this.rentService = rentService;
}
public RentService getRentService() {
return rentService;
}
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();
}
}
- 기존에 있던, rentBook()과 returnBook() 메서드는 RentService 클래스에 옮겨주었다.
- RentService를 Library 생성자를 통해 의존성을 주입시켰다.
RentService
더보기
package lv_4;
public class RentService {
public void rentBook(Book book) {
if (book.rented()) {
System.out.println(book.getTitle() + " : 이미 대여된 책입니다.\n");
} else {
System.out.println(book.getTitle() + " : 대여 완료\n");
book.rent();
}
}
public void returnBook(Book book) {
if (book.rented()) {
System.out.println(book.getTitle() + " : 반납 완료\n");
book.rent();
} else {
System.out.println(book.getTitle() + " : 이미 반납된 책입니다.\n");
}
}
}
- 현재로써는 두 메서드 밖에없는 클래스지만 추후 확장을 고려하여 분리하였다.
Book
더보기
package lv_4;
public class Book {
private String title;
private String author;
private int publishYear;
private boolean isRented;
private int userId;
public Book(String title, String author, int publishYear) {
this.title = title;
this.author = author;
this.publishYear = publishYear;
}
public void rent() {
if(isRented) {
isRented = false;
return;
}
isRented = true;
}
public boolean rented() {
return isRented;
}
public String getTitle() {
return title;
}
public long getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public void resetUserId() {
this.userId = 0;
}
@Override
public String toString() {
return String.format("제목 : %-20s | 저자 : %-30s | 출판 연도 : %-13s",title,author,publishYear);
}
}
User
더보기
package lv_4;
public class User {
private int id;
public User(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
객체의 역할과 책임
Main | Library | Book | RentService | User |
Scanner 객체 생성 | 책 추가 | 책의 정보 보관 | 책 대여 로직 처리 | 사용자 정보 보관 |
Library 객체 생성 | 책 검색 | 책 정보를 문자열로 표현 | 책 반납 로직 처리 | 사용자 정보 제공 |
Book 객체 생성 | 도서 출력 | 책의 정보 제공 | ||
로그인 기능 처리 | ||||
전체 흐름 처리 |
실행 흐름
GPT 분석
`setUserId()`와 `resetUserId()`는 외부에서 Book 속성을 직접 바꿀 수 있다. → 캡슐화가 깨질 수 있다.
- `Book` 객체의 상태가 외부에 의해 너무 쉽게 조작될 수 있다. (ex. 잘못된 시점에 setUserId(0) 호출 가능)
- "왜 바꾸는지"에 대한 의미가 코드에서 드러나지 않는다. (대여인지? 반납인지? 테스트용 변경인지? 알수 없다.)
입력 시책 처리 개선
현재는 `scanner.nextLine()`만 반복되는데, 예외나 공백 처리 등이 없다.
→ 추후 InputView 같은 클래스로 입출력을 분리하면 UI와 도메인을 더욱 명확히 나눌 수 있어요. (MVC로의 확장 가능)