多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 引入 在阎宏博士的《JAVA与模式》一书中开头是这样描述状态(State)模式的: > 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式。 状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。 ## 定义 在很多情况下,一个对象的行为取决于它的一个或多个变化的属性,这些属性我们称之为状态,这个对象称之为状态对象。对于状态对象而已,它的行为依赖于它的状态,比如你要预订房间,那么只有当该房间为空闲时你才能预订,你想入住该房间也只有当你预订了该房间或者该房间为空闲时。对于这样的一个对象,当它在于外部事件产生互动的时候,其内部状态就会发生改变,从而使得他的行为也随之发生改变。 那么何为状态模式呢?所谓状态模式就是允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。 ## 结构 用一句话来表述,状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式的示意性类图如下所示: ![](https://box.kancloud.cn/210b77bae67ec1f338bde6a4f64ed191_506x205.png) 状态模式所涉及到的角色有: * 环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。 * 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。 * 具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。 ## 认识状态模式 **状态和行为** 所谓对象的状态,通常指的就是对象实例的属性的值;而行为指的就是对象的功能,再具体点说,行为大多可以对应到方法上。 状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应的不同功能。也就是说,状态和行为是相关联的,它们的关系可以描述为:状态决定行为。 由于状态是在运行期被改变的,因此行为也会在运行期根据状态的改变而改变。 **行为的平行性** 注意平行线而不是平等性。所谓平行性指的是各个状态的行为所处的层次是一样的,相互独立的、没有关联的,是根据不同的状态来决定到底走平行线的哪一条。行为是不同的,当然对应的实现也是不同的,相互之间是不可替换的。 ![](https://box.kancloud.cn/3a84dcd833cede9072f151e7f1daf728_608x174.png) 而平等性强调的是可替换性,大家是同一行为的不同描述或实现,因此在同一个行为发生的时候,可以根据条件挑选任意一个实现来进行相应的处理。 ![](https://box.kancloud.cn/cefe99f857cf1017a5abecb04f9fbec7_399x228.png) 大家可能会发现状态模式的结构和策略模式的结构完全一样,但是,它们的目的、实现、本质却是完全不一样的。还有行为之间的特性也是状态模式和策略模式一个很重要的区别,状态模式的行为是平行性的,不可相互替换的;而策略模式的行为是平等性的,是可以相互替换的。 **环境和状态处理对象** 在状态模式中,环境(Context)是持有状态的对象,但是环境(Context)自身并不处理跟状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理。 在具体的状态处理类中经常需要获取环境(Context)自身的数据,甚至在必要的时候会回调环境(Context)的方法,因此,通常将环境(Context)自身当作一个参数传递给具体的状态处理类。 客户端一般只和环境(Context)交互。客户端可以用状态对象来配置一个环境(Context),一旦配置完毕,就不再需要和状态对象打交道了。客户端通常不负责运行期间状态的维护,也不负责决定后续到底使用哪一个具体的状态处理对象。 ## 代码实现 首先是状态接口:State ``` public interface State { /** * @desc 预订房间 * @return void */ public void bookRoom(); /** * @desc 退订房间 * @return void */ public void unsubscribeRoom(); /** * @desc 入住 * @return void */ public void checkInRoom(); /** * @desc 退房 * @return void */ public void checkOutRoom(); } ``` 然后是房间类 ``` public class Room { /* * 房间的三个状态 */ State freeTimeState; //空闲状态 State checkInState; //入住状态 State bookedState; //预订状态 State state ; public Room(){ freeTimeState = new FreeTimeState(this); checkInState = new CheckInState(this); bookedState = new BookedState(this); state = freeTimeState ; //初始状态为空闲 } /** * @desc 预订房间 * @return void */ public void bookRoom(){ state.bookRoom(); } /** * @desc 退订房间 * @return void */ public void unsubscribeRoom(){ state.unsubscribeRoom(); } /** * @desc 入住 * @return void */ public void checkInRoom(){ state.checkInRoom(); } /** * @desc 退房 * @return void */ public void checkOutRoom(){ state.checkOutRoom(); } public String toString(){ return "该房间的状态是:"+getState().getClass().getName(); } /* * getter和setter方法 */ public State getFreeTimeState() { return freeTimeState; } public void setFreeTimeState(State freeTimeState) { this.freeTimeState = freeTimeState; } public State getCheckInState() { return checkInState; } public void setCheckInState(State checkInState) { this.checkInState = checkInState; } public State getBookedState() { return bookedState; } public void setBookedState(State bookedState) { this.bookedState = bookedState; } public State getState() { return state; } public void setState(State state) { this.state = state; } } ``` 然后是3个状态类,这个三个状态分别对于这:空闲、预订、入住。其中空闲可以完成预订和入住两个动作,预订可以完成入住和退订两个动作,入住可以退房。 ``` /** * @Description: 空闲状态只能预订和入住 */ public class FreeTimeState implements State { Room hotelManagement; public FreeTimeState(Room hotelManagement){ this.hotelManagement = hotelManagement; } public void bookRoom() { System.out.println("您已经成功预订了..."); hotelManagement.setState(hotelManagement.getBookedState()); //状态变成已经预订 } public void checkInRoom() { System.out.println("您已经成功入住了..."); hotelManagement.setState(hotelManagement.getCheckInState()); //状态变成已经入住 } public void checkOutRoom() { //不需要做操作 } public void unsubscribeRoom() { //不需要做操作 } } ``` ``` /** * @Description: 入住状态房间只能退房 */ public class BookedState implements State { Room hotelManagement; public BookedState(Room hotelManagement) { this.hotelManagement = hotelManagement; } public void bookRoom() { System.out.println("该房间已近给预定了..."); } public void checkInRoom() { System.out.println("入住成功..."); hotelManagement.setState(hotelManagement.getCheckInState()); //状态变成入住 } public void checkOutRoom() { //不需要做操作 } public void unsubscribeRoom() { System.out.println("退订成功,欢迎下次光临..."); hotelManagement.setState(hotelManagement.getFreeTimeState()); //变成空闲状态 } } ``` ``` /** * @Description: 入住可以退房 */ public class CheckInState implements State { Room hotelManagement; public CheckInState(Room hotelManagement) { this.hotelManagement = hotelManagement; } public void bookRoom() { System.out.println("该房间已经入住了..."); } public void checkInRoom() { System.out.println("该房间已经入住了..."); } public void checkOutRoom() { System.out.println("退房成功...."); hotelManagement.setState(hotelManagement.getFreeTimeState()); //状态变成空闲 } public void unsubscribeRoom() { //不需要做操作 } } ``` 最后是测试类 ``` public class Test { public static void main(String[] args) { //有3间房 Room[] rooms = new Room[2]; //初始化 for(int i = 0 ; i < rooms.length ; i++){ rooms[i] = new Room(); } //第一间房 rooms[0].bookRoom(); //预订 rooms[0].checkInRoom(); //入住 rooms[0].bookRoom(); //预订 System.out.println(rooms[0]); System.out.println("---------------------------"); //第二间房 rooms[1].checkInRoom(); rooms[1].bookRoom(); rooms[1].checkOutRoom(); rooms[1].bookRoom(); System.out.println(rooms[1]); } } ``` ## 优点 * 1、封装了转换规则。 * 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 * 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 * 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 * 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。 ## 缺点 * 1、状态模式的使用必然会增加系统类和对象的个数。 * 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 * 3、状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。 ## 适用场景 * 1、对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。 * 2、代码中包含大量与对象状态有关的条件语句 ## 总结 * 1、状态模式允许一个对象基于内部状态而拥有不同的行为。 * 2、Context会将行为委托给当前状态对象。 * 3、状态模式对“开闭原则”支持不是很好