😎

【Java】findRooms関数

2024/01/11に公開

概要

ホテル予約サイトを開発しており、findRooms関数という「指定したチェックイン / アウト日に利用可能な部屋を見つける」ための関数を作った。作っているうちに、全体像がわからなくなってきたので、頭の整理も兼ねてzenn記事を作成する。コードの全体像は、末尾に記載する。

コード解説

ジェネリクス

public Collection<IRoom> findRooms(Date checkInDate, Date checkOutDate)

まず最初に、IRoomをジェネリック型として使う。IRoomは以下のように、部屋番号、値段、部屋タイプ、無料かどうかといった条件を取得できる。ジェネリクスを使うことで、型を指定できるので、実行時のエラーリスクを減少させられる。

public interface IRoom {
    String getRoomNumber();
    Double getRoomPrice();
    RoomType getRoomType();
    boolean isFree();
}

使用可能な部屋

Collection<IRoom> availableRooms = new ArrayList<>();
(中略)
return availableRooms;

次に、使用可能な部屋を格納するための配列を作成する。予約検索した際、使用可能な部屋があれば、この配列に追加される。最後に、使用可能な部屋を追加した値について、returnされる。

roomListのfor loop文

        for (Room room : roomList){
            boolean isAvailable = true;
(中略)
                if (isAvailable) {
                    availableRooms.add(room);
                }

上記のroomListとは、下記コードにて、追加された部屋タイプのこと。ここのloopでは、それぞれのloopに対して、予約チェックをしに行く(後述)構図となっている。まずは、isAvailable(利用可能)がtrueとなっている。そして、これがtrueであれば、利用可能な部屋として、部屋が追加される仕組みとなっている。追加されれば、最後にユーザがチェックイン、チェックアウト日を指定した時に、「この日程だと、この部屋空いてますよ」っていった感じで、部屋追加がされる。

    public void addRoom(String roomNumber, Double price, RoomType roomType) {
        boolean roomExists = roomList.stream().anyMatch(room -> room.getRoomNumber().equals(roomNumber));
        if (!roomExists) {
            Room newRoom = new Room(roomNumber, price, roomType);
            roomList.add(newRoom);
            System.out.println("Room added successfully: " + roomNumber);
        } else {
            System.out.println("Room with number " + roomNumber + " already exists.");
        }
    }

reservationのloop文

各部屋に対して、保管された予約リストをチェックしていく形となる。

            for (Reservation reservation : reservations) {
                if (reservation.getRoom().equals(room)) {
                    if ((checkInDate.before(reservation.getCheckOutDate()) && checkInDate.after(reservation.getCheckInDate())) || (checkOutDate.after(reservation.getCheckInDate()) && checkOutDate.before(reservation.getCheckOutDate()))) {
                        isAvailable = false;
                        break;
                    }

if (reservation.getRoom().equals(room))という条件文では、特定の予約の部屋が、今loopしている部屋と同じかってことをチェックしている。

そしてその次のチェックイン、チェックアウト日のチェックについて、
・入力されたチェックイン日が、「予約リストのチェックアウト日より前」で「チェックイン日より後」
もしくは
・入力されたチェックアウト日が、「予約リストのチェックイン日より後」で「チェックアウト日より前」
であった場合、isAvailableがflaseとなる。そうすることで、予約可否をチェックできる。

全体の流れの復習

前提条件

部屋タイプ:シングル、ダブル
予約リスト:
・シングル:1/1~1/3, 1/5~1/8
・ダブル:1/3~1/4, 1/6~1/9
ユーザの入力日:1/3~1/5

流れ

    // ここでユーザがチェックイン日を1/3、チェックアウト日を1/5で入力
    public Collection<IRoom> findRooms(Date checkInDate, Date checkOutDate) {
       // availableRoomsという配列が作られる。
        Collection<IRoom> availableRooms = new ArrayList<>();
	// roomListは、addRoom関数でシングルタイプ、ダブルタイプが追加される。
	// それぞれのroomに対して、loopをかける。
	// シングルタイプ、ダブルタイプの順でloopを事項するイメージ
	// ToDo: 実際に追加されているか確認する。
        for (Room room : roomList){
	    // 最初はisAvailableがtrueになっている。
	    // trueだと、予約可能な部屋として、availableRoomsに追加される。
	    // そのためのチェックを次のloop文でやる
            boolean isAvailable = true;
	    // ここでは、シングルタイプ、ダブルタイプの順で、部屋が予約されているかチェックをする。
	    // reservationsには、customer, room, checkInDate, checkOutDateといった形で、予約リストが格納されている。
            for (Reservation reservation : reservations) {
	       // これらの予約リストについて、もしloop中の部屋タイプ(シングルorダブル)と一緒であれば、チェックを行う。
                if (reservation.getRoom().equals(room)) {
		    // 実際のloop条件で確認する。ユーザは1/3~1/5と入力。
		    // シングル:1/1~1/3, 1/5~1/8なのでok。
		    // ダブル:1/3~1/4, 1/6~1/9なのでng。
		    // ToDo: ロジック考える
                    if ((checkInDate.before(reservation.getCheckOutDate()) && checkInDate.after(reservation.getCheckInDate())) || (checkOutDate.after(reservation.getCheckInDate()) && checkOutDate.before(reservation.getCheckOutDate()))) {
		        // ToDo: ここ修正。ok、ngなものの処理が違うかも
                        isAvailable = false;
                        break;
                    }
                }
		// 最後に、isAvailableなものについては、availableRoomsとして追加される。
                if (isAvailable) {
                    availableRooms.add(room);
                }
            }
        }
	// availableRoomsに追加されたものがreturnされる。
        return availableRooms;
    }

ToDo

  • if ((checkInDate.before等の条件チェックを確認する。自分が意図した通りに、チェックがかかっていないかも
  • 上記のチェックで、ok / ngだった時の処理内容が合っていないかも。ここのチェックも確認する。
  • 上記完了後、実際にテストデータを追加して、想定通りに動くか確認する。上記例だと、シングルタイプのみが返ってくるはず。
  • 間違っていた場合、以下の通り作業
    • roomListで、シングルとダブルタイプがあるか
    • reservationsで、上記例の3つの予約が入っているか
    • if ((checkInDate.beforeのチェックが機能して、想定通りにtrueかfalseを返しているか
    • その後、availableRoomsに格納する / しないものをしっかり整理できているか

コード全体

    public Collection<IRoom> findRooms(Date checkInDate, Date checkOutDate) {
        Collection<IRoom> availableRooms = new ArrayList<>();
        for (Room room : roomList){
            boolean isAvailable = true;
            for (Reservation reservation : reservations) {
                if (reservation.getRoom().equals(room)) {
                    // 予約した部屋が、reservationsに含まれているか
                    // その予約したreservationsとユーザ入力のcheckindateとcheckoutdateが正しく比較されているか
                    // 比較の結果が、availableroomsに格納される仕組みになっているか
                    if ((checkInDate.before(reservation.getCheckOutDate()) && checkInDate.after(reservation.getCheckInDate())) || (checkOutDate.after(reservation.getCheckInDate()) && checkOutDate.before(reservation.getCheckOutDate()))) {
                        isAvailable = false;
                        break;
                    }
                }
                if (isAvailable) {
                    availableRooms.add(room);
                }
            }
        }
        return availableRooms;
    }

Discussion