PHP面向对象的酒店应用

At the moment I'm programming an object oriented hotel application to learn OOP. I chose this because in my book (PHP Design Patterns from O'Reilly) they programmed a car rental company. Now I'm finished with the basic business logic but I still have some problems.

In the Hotel class are the following methods:

//All public functions, left it hhere cause of the length
checkOut( HotelRoom $room, DateTime $from, DateTime $to )
changeRoom( HotelRoom $oldRoom, HotelRoom $newRoom, HotelCustomer $customer, DateTime $from, DateTime $to)
checkOut( HotelRoom $room, DateTime $from, DateTime $to )

So for every step I do (reserving, changing the room or checkout) I have to pass the HotelRoom as a parameter. Every room has an id and a number. Would it better to implement a method addRoom(HotelRoom $room) and store all rooms in a protected property $rooms array and then only pass the HotelRoom::$id for the methods or is there a better way?

I'm relatively new to OOP and just want to now what is a good practice.

You can do that, but instead of having addRoom(), you could have a function loadRooms() which utilizes the DataBase access object to load all rooms. When it comes to booking you would like to load only the free rooms, same applies for the changing of the rooms. You don't need to do that in checkout().

I would go the following way:

Add object Booking, which has the from, to and reference to the hotel room and to customer Then changeRoom becomes a method of the booking, and it only changes the room, not the dates. Also checkout becomes a method of the booking, as it doesn't make sense to provide dates for the checkout. The room holds when it's available and when is not and should provide methods for just that. The Hotel holds all the rooms and one should always get the room from the hotel object

Hotel
getRoom($id)
getAvailableRooms($from, $to)


HotelRoom
checkIn($from, $to) - proxy to reserve($from, $to) - sets the availability
free($from, $to)

Booking
changeRoom($newRoom)
changeDates($from, $to) // this might be tricky, as it may require changing the room as well
checkOut() // sets the room from the current date to the end of the booking (in case of early checkout) as available

Technically the two approaches is similar. According to the clean coding it is better to pass the room object instead of a number because your code is more readable. Anyone uses your class will know he is working with "rooms" not just a number.

I would not make your Hotel class responsible for your three functions that you have mentioned. They are very specific functions, whereas Hotel is a very broad class.

Consider having a RoomManager and a CustomerManager class. Inject these classes into the Hotel class, and have them responsible for retrieving Room's and Customer's. The Room and Customer class should contain the specific functions that you have outlined:

class Hotel
{
    public $roomManager;
    public $customerManager;

    public function __construct(RoomManager $rm, CustomerManager $cm)
    {
        $this->roomManager = $rm;
        $this->customerManager = $cm;
    }

    // ...
}

class RoomManager
{
    public function getRoom($id)
    {
        // find room where Room->id == $id;
        return $room;
    }

    // some other stuff may become relevant in here
}

class CustomerManager
{
    public function getCustomer($id)
    {
        // find customer where Customer->id == $id;
        return $customer;
    }

    // some other stuff may become relevant in here
}

class Room
{
    public function checkout(DateTime $from, DateTime $to)
    {
        // ...
    }
}

class Customer
{
    private $room;

    public function setRoom(Room $hr)
    {
        $this->room = $hr;
    }
}

Client code would be something like:

// instantiate a Hotel and inject its 2 dependencies
$hotel = new Hotel(new RoomManager, new CustomerManager);

// checkout Room 3
$hotel->roomManager->getRoom(3)->checkout();

// change Customer 2's Room from Room 3 to Room 4
$newRoom = $hotel->roomManager->getRoom(4);
$hotel->customerManager->getCustomer(2)->setRoom($newRoom);

Notice how the responsibility of your classes have become more specific. A Hotel class simply wants to manage the specific components.