重学设计模式(三设计模式-状态模式)

Posted 穆瑾轩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重学设计模式(三设计模式-状态模式)相关的知识,希望对你有一定的参考价值。

1、状态模式

    我们都知道,在java中,对象由数据和作用于该数据的函数组成。数据是属性或特征,而函数通常称之为方法,一旦定义了一个对象,就可以通过它的方法修改它的状态。我们通常使用状态一词来代表对象中独立的、可改变的属性。而对象状态是指对象属性的所有值的组合。调用对象的set方法或者给对象的成员变量赋值,都是在改变对象的状态。

    面对不同的状态,程序可能会做出不同的行为,即从一个状态切换到另外一种状态。对这种有状态的对象编程,传统的解决方案就是:列出这些有限的状态,然后使用if-else或switch-case语句来判断,并做不同的处理。

    如果当一个对象的状态转换条件过于复杂的时候,我们还使用if-else语句的话,如果新增了状态,就要修改代码,这就违背了开闭原则了。注意,这里强调的是状态的切换,比如:酒店预订房间,房间状态的变化。

 

    当遇到这种需要频繁修改状态的时候,就可以考虑使用状态模式。

1.1、什么是状态模式

  • 定义

    状态模式是一种行为设计模式,它允许对象在其内部状态发生变化时改变其行为,即把复杂的“判断逻辑”转移到独立的类中,以表示对象的状态。

状态模式的结构:

    1)抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为;

    2)具体状态(Concrete State)角色:每一个类封装了一个状态对应的行为,可以在需要的情况下进行状态切换。

    3)环境类(Context)角色:它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换;

    状态模式的意图在于:将表示对象状态的逻辑分散到代表状态的不同类中,用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。

1.2、状态模式的优缺点

  • 优点

    1)符合单一职责原则,将特定的状态及其行为都封装到单独的类中;

    2)符合开闭原则,可以在不更改现有状态类或上下文的情况下引入新的状态;

    3)消除了庞大复杂的状态间的切换条件,避免了if...else或switch...case条件逻辑。

  • 缺点

    1)状态模式势必会增加系统类与对象的个数,增加系统的复杂度;

    2)状态模式在状态很少或者很少更改状态的情况下并不很适用。

1.3、创建方式

    我们以酒店房间预订为例。空闲状态下,房间需要预订,才能入住;预订了的房间可以选择退订;已经入住了的房间可以退房;

    在不使用状态模式的情况下,可能会这样实现:

public class HotelDemo 

    public static void main(String[] args) 
    	HotelDemo hotel = new HotelDemo();
    	hotel.setState("空闲");
    	hotel.doAction();
    	hotel.setState("已预订");
    	hotel.doAction();
	

	private String state;
	
	public void setState(String state)
		this.state = state;
	
	
	public void doAction()
		if(state.equals("空闲"))
			System.out.println("空闲状态可以预订");
		else if(state.equals("已预订"))
			System.out.println("已预订状态可以入住或退订");
		else if(state.equals("已入住"))
			System.out.println("已入住状态可以续订或退房");
		
	
	

适用状态模式:

1)抽象状态(State)角色

//抽象状态类
public interface HotelState 

	void handle(HotelContext context); //正向状态
	
	void handleBack(HotelContext context);//反向状态

2)环境类(Context)角色

public class HotelContext 
    
	private HotelState state;
	
	public HotelContext()
		System.out.print("初始化状态:");
		this.state = new FreeState();
	

	public HotelState getState() 
		return state;
	

	public void setState(HotelState state) 
		this.state = state;
	
	
	public void Handle()
		state.handle(this);
	
	
	public void HandleBack()
		state.handleBack(this);
	
	

3)具体状态(Concrete State)角色

//空闲状态
public class FreeState implements  HotelState

	@Override
	public void handle(HotelContext context) 
		System.out.println("当前是空闲状态");
		context.setState(new BookState());
	

	@Override
	public void handleBack(HotelContext context) 
		System.out.println("当前已是空闲状态");
		context.setState(new BookState());
	


//预订状态
public class BookState  implements  HotelState

	@Override
	public void handle(HotelContext context) 
		System.out.println("当前是已预订状态");
		context.setState(new CheckInState());
	

	@Override
	public void handleBack(HotelContext context) 
		System.out.println("当前是已预订状态");
		context.setState(new FreeState());
	
	


//入住状态
public class CheckInState implements  HotelState 

	@Override
	public void handle(HotelContext context) 
		System.out.println("当前是已入住状态");
		context.setState(new CheckOutState());
	

	@Override
	public void handleBack(HotelContext context) 
		System.out.println("当前是已入住状态");
		context.setState(new BookState());
	



//退房状态
public class CheckOutState implements  HotelState 

	@Override
	public void handle(HotelContext context) 
		System.out.println("当前是已退房状态");
		context.setState(new FreeState());
		System.out.println("重新进入空闲状态");
	

	@Override
	public void handleBack(HotelContext context) 
		System.out.println("退房后需重新预订");
		context.setState(new FreeState());
	


//退订状态
public class UnsubscribeState implements  HotelState 

	@Override
	public void handle(HotelContext context) 
        System.out.println("当前状态是退订");
        context.setState(new FreeState());
	

	@Override
	public void handleBack(HotelContext context) 
		System.out.println("当前状态是退订");
		context.setState(new FreeState());
	

4)客户端

public class Clinet 

	public static void main(String[] args) 
		HotelContext hotel = new HotelContext();
		hotel.Handle();//空闲-预订
		hotel.HandleBack();//退订,预订-空闲状态
		hotel.Handle();//重新预订,空闲-预订状态
		hotel.Handle();//预订-入住状态
		hotel.Handle();//入住-退房状态
		hotel.Handle();//退房-空闲状态
	

输出结果:

 

1.4、总结及建议

    状态模式,可以看作是策略模式的延伸。两种模式都是基于组合的,它们通过将一些工作委托给辅助对象来改变上下文的行为,但是策略模式对Strategy的具体实现类有绝对的控制权,即Context要感知Strategy具体类型。而状态模式,Context不需要感知State的具体实现,只需要调用自己的方法,然后委托给State来完成,State会在相应的方法调用时,自动设置状态,这个过程对Context来说是透明的。

应用场景:

    1)当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,可以考虑使用状态模式;

    2)一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时,可以使用状态模式。

java核心库中状态模式的应用:

    javax.faces.lifecycle.LifeCycle#execute()

以上是关于重学设计模式(三设计模式-状态模式)的主要内容,如果未能解决你的问题,请参考以下文章

重学设计模式(三设计模式-备忘录模式)

重学设计模式(三设计模式-备忘录模式)

重学设计模式(三设计模式-解释器模式)

重学设计模式(三设计模式-解释器模式)

重学设计模式(三设计模式-享元模式)

重学设计模式(三设计模式-原型模式)