호텔 예약 프로그램(3)

2023. 10. 27. 17:56Java/project

호텔 예약 프로그램
  • System.out.println()형태로 호텔 예약 프로그램을 만듭니다.
  • UUID, LocalDateTime, LocalDate 사용

변경 사항 

  • 블랙리스트 패턴이 필요없음으로 삭제
  • ViewManagement.java에서 난잡하게 출력했던 출력문을 HotelReservationApp reservationProcess()로 정리
  • 객체 지향적 관점에서 각각의 객체의 역할을 부여하고 이에 해당하는 메서드 정리

모든 코드 페이지의 전문을 보고 싶다면 링크 달아놓겠습니다.

https://github.com/Kminss/hotel-reservation-project

 

GitHub - Kminss/hotel-reservation-project: 내배캠 호텔 예약 시스템 팀 프로젝트

내배캠 호텔 예약 시스템 팀 프로젝트. Contribute to Kminss/hotel-reservation-project development by creating an account on GitHub.

github.com

 

 맡은 역할 : 예약 프로세스

   - 역할에 해당하는 코드만 적어놓을 것이며 팀원들이 적은 코드는 해당 윗 링크에 존재합니다.

   - 예시로 InputManager.java(Sacnner 입출력 관리)는 제외시켰습니다.

 

   1. ViewManagement.java

       - 해당 페이지는 관리 페이지임으로 출력문을 이동했습니다.

       - 해당 페이지는 예약 프로세스에 관련 없는 코드라 생략합니다.(전문 참고)

package com.nbc.hotel.model;

import java.util.List;

public class ViewManagement {


    public static void showFindReservationMenu() {
        System.out.println();
        System.out.println("객실 예약 조회 화면입니다.");
        System.out.println("1. 모든 예약 조회(관리자 기능)");
        System.out.println("2. 내 예약 목록 조회");
        System.out.println("3. 예약 번호로 조회");
        System.out.println("4. 돌아가기");
        System.out.print("입력: ");
    }

    public static void showFindAllReservations(List<Reservation> reservations) {
        System.out.println("모든 예약을 조회합니다.");
        showReservations(reservations);
    }

    public static void showFindMyReservations(List<Reservation> reservations) {
        System.out.println("내 예약 목록을 조회합니다.");
        showReservations(reservations);
    }

    public static void showFindReservation() {
        System.out.println("예약 번호로 조회합니다.");
        System.out.println("예약 번호를 입력해주세요.");
    }

    public static void showReservations(List<Reservation> reservations) {
        System.out.println("[예약 정보]");
        reservations.forEach(reservation -> System.out.println(reservation.getReservationInfo()));
    }

    public static void showFindReservationClose() {
        System.out.println("예약 조회를 종료합니다.");
    }
    public static void showFindReservationFailed() {
        System.out.println("예약 번호로 조회할 수 없습니다.");
    }


    public static void showCancelReservation() {
        System.out.println("========예약 취소하기========");
        System.out.println("취소하실 객실의 예약 번호를 입력해주세요.");
        System.out.print("입력 > ");
    }

    public static void showCancelReservationSuccess(Reservation reservation) {
        System.out.println("===========success===========");
        System.out.println("객실 예약이 취소 되었습니다.");
        System.out.println("===========예약정보===========");
        System.out.println("==============================");
        System.out.printf(reservation.getReservationInfo());
    }

    public static void showCancelReservationFailed(String reason) {
        System.out.println("===========fail===========");
        System.out.println("객실 예약 취소가 실패하였습니다.");
        System.out.println("===========사유===========");
        System.out.println(reason);
        System.out.println("==========================");
    }
}

 

  2. Reservation.java

       - LocalDate reservationDate // 예약 날짜

       - LocalDateTime reservationDate2 // 예약 당일

       - 이전에 사용했던 메서드 hasMoney()등등은 Reservation.java에서 이루어지지 않도록 변경했습니다.

package com.nbc.hotel.model;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;


public class Reservation {

    private UUID uuid;
    private Room room;
    private String customerName;
    private String customerPhoneNumber;
    private LocalDateTime reservationDate;

    public Reservation(UUID uuid, Room room, String customerName, String customerPhoneNumber, LocalDateTime reservationDate) {
        this.uuid = uuid;
        this.room = room;
        this.customerName = customerName;
        this.customerPhoneNumber = customerPhoneNumber;
        this.reservationDate = reservationDate;
    }

    public UUID getUuid() {
        return uuid;
    }

    public String getReservationInfo () {
        return String.format("예약일: %s %n예약번호: %s %n %s 예약자 명: %s %n예약자 휴대폰번호: %s %n",
                reservationDate.format(DateTimeFormatter.ISO_DATE),
                uuid,
                room.getRoomInfo(),
                customerName,
                customerPhoneNumber);
    }


    public UUID getReservationId () {
        return uuid;
    }
}

 

   3. Room.java

     - getInfo()추가 

package com.nbc.hotel.model;

import java.util.List;

public class Room {
    Double size;
    Double price;
    List<Reservation> reservations;

    public Room(Double size, Double price) {
        this.size = size;
        this.price = price;
    }

    public Double getSize() {
        return size;
    }

    public Double getPrice() {
        return price;
    }

    public String getRoomInfo() {
        return String.format("객실 크기: %.1f %n 객실 금액: %.1f %n", size, price);
    }
}

 

  4. Customer.java

     - 출력문에 필요없는 getter, setter정리

package com.nbc.hotel.model;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class Customer extends User{

    private String name;	
    private String phoneNumber;
    private Double money;
    private List<UUID> reservationIds;

    public Customer(String name, String phoneNumber, Double money) {
        this.name = name;
        this.phoneNumber = phoneNumber;
        this.money = money;
        this.reservationIds = new ArrayList<>();
    }
    public Customer(String name, String phoneNumber, Double money, List<UUID> reservationIds) {
        this(name, phoneNumber, money);
        this.reservationIds = reservationIds;
    }

    public String getName() {
        return name;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public Double getMoney() {
        return money;
    }

    public List<UUID> getReservationIds() {
        return reservationIds;
    }
}

 

   5. Hotel.java

     - 블랙리스트 패턴 삭제

     - checkBlackListPhoneNumber(), checkCustomerName(), checkMoeny() 

     - Hotel.java에서 이루어지는 기존 메서드들 삭제

     - 예약조회, 모든 예약 조회 메서드

package com.nbc.hotel.model;


import com.nbc.hotel.exception.ReservationNotFoundException;

import java.util.ArrayList;
import java.util.List;


import java.util.ArrayList;
import java.util.List;

import java.util.UUID;

public class Hotel {
    private List<Room> rooms;
    private List<Reservation> reservations = new ArrayList<>();
    private Double money;
    Boolean cancelReservations;

    public void cancelReservation(Reservation targetReservation) throws ReservationNotFoundException {
        if (!reservations.remove(targetReservation)) {
            throw new ReservationNotFoundException();
        }
    }

    /**
     * 예약이 존재하면 예약을 돌려주고, 없다면 ReservationNotFoundException 던진다
     *
     * @param reservationId
     * @return
     */
    public Reservation findReservationByUUID(UUID reservationId) {
        return reservations
                .stream()
                .filter(reservation -> reservation.getReservationId().compareTo(reservationId) == 0)
                .findFirst()
                .orElseThrow(ReservationNotFoundException::new);
    }


    public List<Reservation> findAllReservations() {
        return reservations;
    }

    /**
     * @param uuids
     * @return
     */
    public List<Reservation> findReservationsByUUIDs(List<UUID> uuids) {
        return reservations
                .stream()
                .filter(reservation -> uuids.contains(reservation.getUuid()))
                .toList();
    }
}

   6. HotelReservationApp.java

     - 모든 입,출력단을 HotelReservationApp에서 관리

     - 예약, 예약 조회, 예약 취서 프로세스 관련 메서드들을 가집니다.

     - 이에 대한 메서드 설명은 주석 처리해놨습니다.

package com.nbc.hotel.app;

import com.nbc.hotel.exception.ReservationNotFoundException;
import com.nbc.hotel.model.*;
import com.nbc.hotel.util.Util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

import static com.nbc.hotel.model.ViewManagement.showReservationInfo;
import static com.nbc.hotel.model.ViewManagement.showSelectedDateRooms;
import static com.nbc.hotel.util.Util.isValidDate;

public class HotelReservationApp {
    private Hotel hotel;
    private Customer customer;

    public HotelReservationApp(Customer customer) {
        hotel = new Hotel();
        this.customer = customer;
    }

    public void mainProcess() {
        while (true) {
            try {
                System.out.println("호텔 기능을 선택해주세요. ");
                System.out.println("1. 예약 2. 취소 3. 조회");
                int select = InputManager.inputMenuNumber(3);
                switch (select) {
                    case 0:
                        reservationProcess();
                        break;
                    case 1:
                        // 예약 취소
                        cancelReservationProcess();
                        break;
                    case 2:
                        // 예약 조회
                        findReservationProcess();
                        break;
                    default:
                        System.out.println("잘못된 입력입니다. 다시 시도해주세요");
                        break;
                }
            } catch (Exception e) {
                System.out.println("오류가 발생했습니다. " + e.getMessage());
            }
        }
    }

    private void reservationProcess() throws Exception {
        // 입력단 예외 상황 해결을 위해 makeReservation()으로 옮김
        System.out.println("날짜를 입력해주세요 : ");
        String selectDate = InputManager.handleInput();
        makeReservation(selectDate);

        // 날짜 입력 로직

        System.out.println("============================");
        System.out.println("선택하고 싶은 방을 골라주세요 : ");
        int selectRoomNumber = InputManager.inputMenuNumber(hotel.getRooms().size());
        // room 확인 및 예약 진행 로직

        // 이미 예약된 방인지 검증
        if (isReserved(selectDate, selectRoomNumber))
            throw new Exception("이미 예약된 방입니다.");

        System.out.println("=====1. 예약하기 2. 취소하기=====");
        int finalCheck = InputManager.inputMenuNumber(2);
        ViewManagement.showReservationOrCancel(finalCheck);
        // 해당 사항으로 최종확인 여부를 물음

        System.out.println("예약자 성함을 알려주세요 : ");
        String customerName = InputManager.handleInput();
        hotel.checkCustomerName(customerName);

        // 예약자 이름 확인 로직

        System.out.println("예약자 전화번호를 입력해주세요 : (01*-****-****만 가능)");
        String customerPhoneNumber = InputManager.handleInput();
        boolean isValidPhoneNumber = hotel.checkPhoneNumber(customerPhoneNumber);

        if (!isValidPhoneNumber) {
            throw new Exception("올바르지 않은 전화번호입니다.");
        } else {
            double selectRoomPrice = hotel.getRooms().get(selectRoomNumber).getPrice();
            if (hotel.checkMoney(customer, selectRoomPrice)) {
                finalReservation(selectDate, selectRoomNumber,
                        customerName, customerPhoneNumber);
            }
        }
    }

    public void finalReservation(String selectDate, int selectRoomNumber, String customerName,
                                 String customerPhoneNumber) {
        Reservation reservation = new Reservation(UUID.randomUUID(),
                hotel.getRooms().get(selectRoomNumber), customerName,
                customerPhoneNumber, LocalDate.parse(selectDate), LocalDateTime.now());
        hotel.getRooms().get(selectRoomNumber).addReservation(reservation);
        System.out.println(customerName + "님 예약 완료되셨습니다.");
        System.out.println(customerName + "님 예약 번호는" + reservation.getUUID() + "입니다.");

        hotel.getReservations().add(reservation);
        showReservationInfo(reservation);
    }


    private boolean isReserved(String selectDate, int selectRoomNumber) {
        return hotel.getRooms().get(selectRoomNumber).isReserved(LocalDate.parse(selectDate));
    }

    public void makeReservation(String selectDate) throws Exception {
        try {
            // selectDate의 유효성을 검사합니다.
            if (!isValidDate(selectDate)) {
                // 만약 날짜를 파싱해서 제대로된 yyyy-MM-dd가 들어가지 않을때
                throw new IllegalArgumentException("유효하지 않은 날짜 형식입니다.");
            }
        } catch (IllegalArgumentException e) {
            System.out.println("예외 발생: " + e.getMessage());
            System.out.println("=========다시 실행합니다=========");
            throw new Exception();
        }
        showSelectedDateRooms(selectDate, hotel.getRooms());
    }

    /**
     * 예약 조회 컨트롤 메서드
     */
    public void findReservationProcess() {
        ViewManagement.showFindReservationMenu();
        Integer menuNumber = InputManager.inputMenuNumber(4);

        switch (FindMenu.toMenu(menuNumber)) {
            case FIND_ALL -> findAllReservationsProcess();
            case FIND_OWN -> findOwnReservationsProcess();
            case FIND_UUID -> findOneReservationProcess();
            case QUIT -> findReservationQuitProcess();
        }
    }

    public void findAllReservationsProcess() {
        List<Reservation> allReservations = hotel.findAllReservations();
        ViewManagement.showFindAllReservations(allReservations);
    }

    public void findOwnReservationsProcess() {
        List<Reservation> reservations = hotel.findReservationsByUUIDs(customer.getReservationIds());
        ViewManagement.showFindMyReservations(reservations);
    }

    public void findOneReservationProcess() {
        ViewManagement.showFindReservation(); // 메뉴 출력
        try {
            UUID uuid = InputManager.inputUUID(); // 입력 받음
            Reservation reservation = hotel.findReservationByUUID(uuid); // 찾음
            ViewManagement.showReservations(List.of(reservation)); // 출력
        } catch (ReservationNotFoundException exception) {
            System.out.println("잘못된 UUID 입력입니다.");
        }
    }

    public void findReservationQuitProcess() {
        ViewManagement.showFindReservationClose();
    }


    public void cancelReservationProcess() {
        ViewManagement.showCancelReservation();
        String reservationId = InputManager.handleInput();

        try {
            Reservation reservation = hotel.findReservationByUUID(Util.converStringToUuid(reservationId));
            hotel.cancelReservation(reservation);
            ViewManagement.showCancelReservationSuccess(reservation);
            mainProcess();
        } catch (ReservationNotFoundException exception) {
            ViewManagement.showCancelReservationFailed(exception.getMessage());
        }
    }
}

 

-예약 화면 예시

호텔을 예약하시겠습니까? 
1. 예약 2. 취소 3. 조회
1
날짜를 입력해주세요 : 
2023-11-23
============================
해당 날짜 : 2023-11-23 방 예약
============================
1. size: 1 price: $90.0
2. size: 1 price: $110.0
3. size: 1 price: $130.0
4. size: 1 price: $190.0
5. size: 2 price: $140.0
6. size: 2 price: $160.0
7. size: 2 price: $200.0
8. size: 2 price: $220.0
============================
선택하고 싶은 방을 골라주세요 : 
5
======해당 방이 맞으십니까?======
=========2023-11-23=========
size : 2 price : $140.0
=====1. 예약하기 2. 취소하기=====
1
예약자 성함을 알려주세요 : 
papa
예약자 전화번호를 입력해주세요 : 
010-2222-3333
papa님 예약 완료되셨습니다.
papa님 예약 번호는 1입니다.
================================
name : papa
phoneNumber : 010-2222-3333
reservationId : 1
reservationDate : 2023-11-23
reservationDate2 : 2023-11-23
reservationUUID : f3d268a8-d64b-45cd-b8ad-46704659b489
reservationPrice : 140.0
roomSize : 2.0
================================

 

프로젝트 아쉬웠던 점

   

   1. 요구사항 파악 :

       전화번호 제한 정규표현식(01*-****-****)을 착각해서 블랙리스트 패턴을 만들라고 생각했다....

       좀 제대로 읽어보는 걸로... ㅎㅎ

   2. 객체 지향적 관점 :

      코드 전문을 빠르게 만들어 올리는 것을 주력으로 해 ViewMangement쪽에 출력문을 다 넣어놨는데

      팀원들이 싱글톤 및 메모리 관련 측면에서 설계를 하다보니 많이 배웠습니다.

      객체 지향적 관점에 대해서 따로 공부해 봐야겠다는 생각을 듭니다.

  3. 협업툴 (Git) :

      사용한다고 사용했는데 pull request라든지 merge과정을 팀원들한테 물어보면서 했습니다.

      이 과정에서 merge하는데 저의 branch에서 만든 코드와 main branch의 merge과정이 계속 안되어서

     시간을 좀 오래 썼다는점...?이 아쉬웠습니다.(팀원분들 너무 감사합니다...)

 

'Java > project' 카테고리의 다른 글