検証



interface IState{
	public function reservation();
	public function checkin();
	public function checkout();
}


class ReservState implements IState{
	private $subject;
	
	public function __construct(Hotel $subject){
		$this->subject = $subject;
	}
	
	public function reservation(){
		echo '予約済みです。<br>';
	}
	
	public function checkin(){
		echo 'チェックインし、滞在状態になりました。<br>';
		$this->subject->changeState(new StayState($this->subject));
	}
	
	public function checkout(){
		echo '予約状態でチェックアウトはできません。<br>';
	}
}


class StayState implements IState{
	private $subject;
	
	public function __construct(Hotel $subject){
		$this->subject = $subject;
	}
	
	public function reservation(){
		echo '別件で予約状態にします。<br>';
	}
	
	public function checkin(){
		echo 'チェックイン済みです。<br>';
	}
	
	public function checkout(){
		echo 'チェックアウトして、未予約状態になりました。<br>';
		$this->subject->changeState(new UnreservState($this->subject));
	}
}


class UnreservState implements IState{
	private $subject;
	
	public function __construct(Hotel $subject){
		$this->subject = $subject;
	}
	
	public function reservation(){
		echo '予約して、予約状態になりました。<br>';
		$this->subject->changeState(new ReservState($this->subject));
	}
	
	public function checkin(){
		echo '空き室があれば滞在状態になります。空き室がなければ未予約状態のままです。<br>';
	}
	
	public function checkout(){
		echo 'チェックインしていないのでチェックアウトできません。<br>';
	}
}


class Hotel{
	
	private $state; // <IState>
	public function __construct(){
		$this->state = new UnreservState($this); // 未予約状態
	}
	
	/**
	 * 状態を変更する
	 * @param IState $state 状態クラスのインスタンス
	 */
	public function changeState(IState $state){
		$this->state = $state;
	}
	
	public function reserveAction(){
		$this->state->reservation();
	}
	
	public function checkinAction(){
		$this->state->checkin();
	}
	
	public function checkoutAction(){
		$this->state->checkout();
	}
}

$hotel = new Hotel();
$hotel->reserveAction();
$hotel->checkinAction();
$hotel->checkinAction();
$hotel->checkoutAction();


出力

予約して、予約状態になりました。
チェックインし、滞在状態になりました。
チェックイン済みです。
チェックアウトして、未予約状態になりました。