java-状态模式

       状态模式的定义为:当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了它的类。

       状态模式比较容易理解: 就是把各个状态定义成类,对状态的更改封装到状态类里,对更改进行的限制也封装到相应的类里。状态模式的好处就是结构清晰,封装性比较好,也容易扩展。

       网上很多例子都是用红绿灯来做状态模式的例子。指示灯有红黄绿三种颜色,相当于三种状态,然后定义三个状态类,在三个状态类里定义指示灯的改变。这样比较清晰,比如说红灯里面的改变颜色方法就是变成绿灯。个人觉得这个例子不太好。。。  比如我完全可以这样:

changeState(int i){
     return (i + 1)%3;
}

 然后用三个数字代表三种颜色,好像更好更简单。。。

      个人觉得状态模式更适合这种场景:  多种状态,多种操作,并且每种操作对应的状态改变都有限制。  比如说设计之禅上面的电梯例子,再比如说我下面代码里的订房间的例子。  房间有多种状态,这里暂定三种:空闲,被预订,已入住。   如果不用状态模式的话,那么订房操作就是各种if--else判断。如果逻辑再复杂点,如果状态再多点,如果针对每种状态的逻辑差异再大点。。。。    一路if-else搞下去,一个方法上千行不是梦。。。。    这样编码的时候可能不觉得比状态模式好多少,因为你状态模式还有很多类呢,也是逻辑复杂,代码一点不比我少。但是。。  如果后期维护呢,我是见过一个方法500行代码的,要想修改一下,真的能把人逼疯。。。。

      状态模式个人觉得特别容易理解,代码也清晰简单,一个状态接口,定义改变状态的各种操作:

/**  
* State:状态接口
* @author xuejupo  [email protected] 
* create in 2015-12-30 下午2:46:59  
*    
*/
interface State{
	/**  
	* bookRoom:  预定房间
	* void  返回类型   
	*/
	void bookRoom();
	/**  
	* unbookRoom:  取消预定
	* void  返回类型   
	*/
	void unbookRoom();
	/**  
	* checkinRoom:  入住房间
	* void  返回类型   
	*/
	void checkinRoom();
	/**  
	* checkoutRoom:  退房
	* void  返回类型   
	*/
	void checkoutRoom();
}

 然后就是各种实体状态类:

/**  
* FreeState: 房间的空闲状态
* @author xuejupo  [email protected] 
* create in 2015-12-30 下午2:54:00  
*    
*/
class FreeState implements State{
	private HotelRoom room;
	public FreeState(HotelRoom room){
		this.room = room;
	}
	@Override
	public void bookRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间空闲可预定,您已经订了这个房间");
		//改变房间状态
		this.room.setState(this.room.getIsBookedState());
	}

	@Override
	public void unbookRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间空闲,不能取消预定");
	}

	@Override
	public void checkinRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间空闲,可以直接入住,只要交钱就行");
		this.room.setState(this.room.getCheckInState());
	}

	@Override
	public void checkoutRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间空闲,不能直接退房");
	}
}

/**  
* IsBooked: 房间处于已被预定状态
* @author xuejupo  [email protected] 
* create in 2015-12-30 下午2:55:26  
*    
*/
class IsBookedState implements State{
	private HotelRoom room;
	public IsBookedState(HotelRoom room){
		this.room = room;
	}
	@Override
	public void bookRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间已经被预定");
	}

	@Override
	public void unbookRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间已经被预定,可以取消预定");
		this.room.setState(this.room.getFreeState());
	}

	@Override
	public void checkinRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间已预定,可以入住");
		this.room.setState(this.room.getCheckInState());
	}

	@Override
	public void checkoutRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间已预定状态,不能直接退房");
	}
}

/**  
* CheckInState: 房间是已入住状态
* @author xuejupo  [email protected] 
* create in 2015-12-30 下午2:56:25  
*    
*/
class CheckInState implements State{
	private HotelRoom room;
	public CheckInState(HotelRoom room){
		this.room = room;
	}
	@Override
	public void bookRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间住人了,不能再预定了");
	}

	@Override
	public void unbookRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间住人了,取消预定了");
	}

	@Override
	public void checkinRoom() {
		// TODO Auto-generated method stub
		System.out.println("房间住人了,不能再入住了");
	}

	@Override
	public void checkoutRoom() {
		// TODO Auto-generated method stub
		System.out.println("您可以正常退房!");
		//改变房间状态到空闲
		this.room.setState(this.room.getFreeState());
	}
	
}

 房间接口(状态更改操作的实施者接口):

/**  
* Room:房间接口
* @author xuejupo  [email protected] 
* create in 2015-12-30 下午2:46:59  
*    
*/
interface Room{
	/**  
	* bookRoom:  预定房间
	* void  返回类型   
	*/
	void bookRoom();
	/**  
	* unbookRoom:  取消预定
	* void  返回类型   
	*/
	void unbookRoom();
	/**  
	* checkinRoom:  入住房间
	* void  返回类型   
	*/
	void checkinRoom();
	/**  
	* checkoutRoom:  退房
	* void  返回类型   
	*/
	void checkoutRoom();
}

 具体房间类:

/**  
* HotelRoom: 旅馆房间
* @author xuejupo  [email protected] 
* create in 2015-12-30 下午3:06:08  
*    
*/
class HotelRoom implements Room{
	/*  
     * 房间的四个状态  
     */  
    private State freeState;    //空闲状态  
    private State checkInState;     //入住状态  
    private State isBookedState;      //预订状态  
    private State state; 			//房间现有的状态
    //在构造函数里面初始化
    public HotelRoom(){
    	this.freeState = new FreeState(this);
    	this.checkInState = new CheckInState(this);
    	this.isBookedState = new IsBookedState(this);
    	this.state = new FreeState(this);
    }
	@Override
	public void bookRoom() {
		// TODO Auto-generated method stub
		this.state.bookRoom();
	}

	@Override
	public void unbookRoom() {
		// TODO Auto-generated method stub
		this.state.unbookRoom();
	}

	@Override
	public void checkinRoom() {
		// TODO Auto-generated method stub
		this.state.checkinRoom();
	}

	@Override
	public void checkoutRoom() {
		// TODO Auto-generated method stub
		this.state.checkoutRoom();
	}

	public final State getFreeState() {
		return freeState;
	}

	public final State getCheckInState() {
		return checkInState;
	}

	public final State getIsBookedState() {
		return isBookedState;
	}

	public final State getState() {
		return state;
	}

	public final void setState(State state) {
		this.state = state;
	}
	
}

 测试代码:

/**  
 *  StateTest : 状态模式
 * @author xuejupo  [email protected] 
 * create in 2015-12-30 下午2:46:43    
 */

public class StateTest {

	/**  
	 * main: 
	 * @param args 
	 * void  返回类型   
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//初始化一个房间
		Room room = new HotelRoom();
		room.bookRoom();
		room.bookRoom();
		room.checkinRoom();
		room.bookRoom();
		room.checkoutRoom();
		room.checkinRoom();
		room.bookRoom();
	}
}

 结果:

扫描二维码关注公众号,回复: 704831 查看本文章
房间空闲可预定,您已经订了这个房间
房间已经被预定
房间已预定,可以入住
房间住人了,不能再预定了
您可以正常退房!
房间空闲,可以直接入住,只要交钱就行
房间住人了,不能再预定了

 清晰明白!

      ps(个人感受):

       第一次接触状态模式的示例代码是红绿灯那个实例。个人觉得那个实例不好,容易把人搞晕。。。我当初学状态模式的时候就被他搞得挺晕。。。  当时觉得,红绿灯这么简单的问题也用这么多类。。。。 这不是把简单问题复杂化了嘛。。。

     如果老大让我做一个红绿灯的项目,我多半不会用状态模式。第一:他的状态特别少,就三个状态,要是用状态模式就要多写三个类,还有一个接口。。  如果不用状态模式,我一个int搞定;第二,他的状态之间转换特别简单,我完全可以一个方法搞定,最多多写点注释,比多用几个类要简单清晰得多。而且,感觉后期维护看起来也比较清晰;第三,红绿灯项目是不用考虑增加状态的,像旅店房间可能会增加几个状态,比如未打扫状态,或者预定未付定金状态等等,但是红绿灯不用考虑这些,所以设计的时候可以不考虑扩展性。

猜你喜欢

转载自709002341.iteye.com/blog/2269015