设计模式:状态模式(Status)
在介绍状态模式之前,我们先来看这样一个实例:你公司力排万难终于获得某个酒店的系统开发项目,并且最终落到了你的头上。下图是他们系统的主要工作(够简单)。
当你第一眼看到这个系统的时候你就看出来了这是一个状态图,每个框框都代表了房间的状态,箭头表示房间状态的转换。分析如下:房间有三个状态:空闲、已预订、已入住,状态与状态之间可以根据客户的动作来进行转换。定义每个状态的值。
public static final int FREEMTIME_STATE = 0; //空闲状态
public static final int BOOKED_STATE = 1; //已预订状态
public static final int CHECKIN_STATE = 2; //入住状态 int state = FREEMTIME_STATE; //初始状态
通过客户的动作将每个状态整合起来,对于这个“最简单”的方式肯定是if…else if…else啦!所以这里我们就通过动作将所有的状态全面整合起来。分析得这里有四个动作:预订、入住、退订、退房。如下:
/**
* @desc 预订
* @return void
*/
public void bookRoom(){
if(state == FREEMTIME_STATE){ //空闲可预订
if(count > 0){
System.out.println("空闲房间,完成预订...");
state = BOOKED_STATE; //改变状态:已预订
count --;
//房间预订完了,提示客户没有房源了
if(count == 0){
System.out.println("不好意思,房间已经预订完,欢迎您下次光临...");
}
}
else{
System.out.println("不好意思,已经没有房间了....");
}
}
else if(state == BOOKED_STATE){
System.out.println("该房间已经被预订了...");
}
else if(state == CHECKIN_STATE){
System.out.println("该房间已经有人入住了...");
}
} /**
* @desc 入住
* @return void
*/
public void checkInRoom(){
if(state == FREEMTIME_STATE){
if(count > 0){
System.out.println("空闲房间,入住...");
state = CHECKIN_STATE; //改变状态:已预订
count --;
//房间预订完了,提示客户没有房源了
if(count == 0){
System.out.println("不好意思,房间已经预订完,欢迎您下次光临...");
}
}
else{
System.out.println("不好意思,已经没有房间了....");
} }
else if(state == BOOKED_STATE){
if("如果该房间是您预订的"){
System.out.println("入住....");
state = CHECKIN_STATE;
}
else{
System.out.println("您没有预订该房间,请先预订...");
}
}
else if(state == CHECKIN_STATE){
System.out.println("该房间已经入住了...");
}
} /**
* @desc 退订
* @return void
*/
public void unsubscribeRoom(){
if(state == FREEMTIME_STATE){
}
else if(state == CHECKIN_STATE){ }
else if(state == BOOKED_STATE){
System.out.println("已退订房间...");
state = FREEMTIME_STATE;
count ++;
}
} /**
* @desc 退房
* @return void
*/
public void checkOutRoom(){
if(state == FREEMTIME_STATE){ }
else if(state == BOOKED_STATE){ }
else if(state == CHECKIN_STATE){
System.out.println("已退房..");
state = FREEMTIME_STATE;
count++;
}
}
对于上面的代码你是否满意呢?满意那么你就没有必要往下看了,不满意我们接着讲。
正当你完成这个“复杂”if..else if …else时(我都写了一会儿),你客户说,我们需要将某些房间保留下来以作为备用(standbyState),于是你发现你悲剧了,因为你发现你要在所有的操作里都要判断该房间是否为备用房间。当你老大经过你身边的时候发现你正在纠结怎么改的时候,你老大就问你为什么不换一个角度思考以状态为原子来改变它的行为,而不是通过行为来改变状态呢?于是你就学到了状态模式。
一、模式定义
在很多情况下,一个对象的行为取决于它的一个或多个变化的属性,这些属性我们称之为状态,这个对象称之为状态对象。对于状态对象而已,它的行为依赖于它的状态,比如你要预订房间,那么只有当该房间为空闲时你才能预订,你想入住该房间也只有当你预订了该房间或者该房间为空闲时。对于这样的一个对象,当它在于外部事件产生互动的时候,其内部状态就会发生改变,从而使得他的行为也随之发生改变。
那么何为状态模式呢?所谓状态模式就是允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
二、模式结构
下图为状态模式的UML图。
状态模式包含如下角色:
Context: 环境类。可以包括一些内部状态。
State: 抽象状态类。State定义了一个所有具体状态的共同接口,任何状态都实现这个相同的接口,这样一来,状态之间就可以互相转换了。
ConcreteState: 具体状态类。具体状态类,用于处理来自Context的请求,每一个ConcreteState都提供了它对自己请求的实现,所以,当Context改变状态时行为也会跟着改变。
三、模式实现
依然是上面那个酒店的实例。对于该实例的UML图如下:
首先是状态接口: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个状态类,这个三个状态分别对于这:空闲、预订、入住。其中空闲可以完成预订和入住两个动作,预订可以完成入住和退订两个动作,入住可以退房。
/**
* @project: design_state
* @author chenssy
* @date 2013-8-24
* @Description: 空闲状态只能预订和入住
*/
public class FreeTimeState implements State { Room hotelManagement; public FreeTimeState(Room hotelManagement){
this.hotelManagement = hotelManagement;
} public void bookRoom() {
System.out.println("您已经成功预订了...");
.setState(hotelManagement.getBookedState()); //状态变成已经预订
} public void checkInRoom() {
System.out.println("您已经成功入住了...");
hotelManagement.setState(hotelManagement.getCheckInState()); //状态变成已经入住
} public void checkOutRoom() {
//不需要做操作
} public void unsubscribeRoom() {
//不需要做操作
} }
/**
* @project: design_state
* @author chenssy
* @date 2013-8-24
* @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()); //变成空闲状态
} }
/**
* @project: design_state
* @author chenssy
* @date 2013-8-24
* @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、状态模式对“开闭原则”支持不是很好。
设计模式:状态模式(Status)的更多相关文章
- 14. 星际争霸之php设计模式--状态模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- [Head First设计模式]生活中学设计模式——状态模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- JAVA 设计模式 状态模式
用途 状态模式 (State) 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式是一种行为型模式. 结构
- 深入浅出设计模式——状态模式(State Pattern)
模式动机 在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的 (stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的.当一个这样的 ...
- C++设计模式——状态模式
前言 在实际开发中,我们经常会遇到这种情况:一个对象有多种状态,在每一个状态下,都会有不同的行为.那么在代码中我们经常是这样实现的. typedef enum tagState { state, st ...
- C#设计模式--状态模式
设计模式: 状态模式(State Pattern) 简单介绍: 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式. 在状态模式中,我们创建表示 ...
- Java设计模式—状态模式
状态模式又是一个比较难的设计模式 定义如下: 当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类. 个人理解:通俗的讲,状态模式就是状态的改变引起了行为的改变,但是,我们只能看到行为的 ...
- 设计模式-状态模式(State Pattern)
本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 状态模式简介 状态模式允许一个对象在其内部状态改变的时候改变它的行为,他的内部会存着好几种状态, ...
- 设计模式-状态模式(State)
状态模式是行为模式的一种,状态模式允许改变对象内部状态来改变对象的行为. 角色和职责: 1.上下文(Context)-Order: 拥有内部的状态 2.状态接口(Status)-State: 一 ...
随机推荐
- Ubuntu安装之pycharm安装
什么??公司要用Ubuntu(乌班图)?不会用??怎么进行python开发??? 乌班图操作系统下载地址:http://releases.ubuntu.com/18.04/ubuntu-18.04.1 ...
- Linux之zookeeper开机启动
1.用cd 命令切换到/etc/rc.d/init.d/目录下 [root@bogon ~]# cd /etc/rc.d/init.d 2.用touch zookeeper创建一个文件 [root@b ...
- JavaWeb-SpringSecurity图片验证ImageCode
系列博文 项目已上传至guthub 传送门 JavaWeb-SpringSecurity初认识 传送门 JavaWeb-SpringSecurity在数据库中查询登陆用户 传送门 JavaWeb-Sp ...
- python3 输入与输出
pyhon3 io 输入和输出myread=open('E:/路径.txt')#open()会将返回一个file对象mywrite=open('E:/3/路径.txt','w')#后面w是如果文件存在 ...
- Go 结构体与初始化
Go 通过类型别名(alias types)和结构体的形式支持用户自定义类型. 结构体是复合类型,当需要定义类型,它由一系列属性组成,每个属性都有自己的类型和值的时候,就应该使用结构体,它把数据聚集在 ...
- layui按回车键实现表单提交
layui中标准用法如下: <form class="layui-form"> <input type="button" id="q ...
- 爬取百度网盘资源报user is not authorized, hitcode:119
爬取百度网盘资源报user is not authorized, hitcode:119 一.总结 一句话总结: 可能是百度网盘禁止非客户端环境下载大文件,所以将请求头改为客户端:'User-Agen ...
- 一、初识Spring Boot框架
一.搭建Spring Boot环境 1.选择Project,选择Spring Initializr 2.选择Sdk与默认url 3.点击 Next 4.修改一下Group信息和Artifacet,Ne ...
- 如何在gradle项目中添加额外非开源jar包并提交代码
前提:项目开发中,遇到一个地方需要用到公司自定义的jar包,然后要放到代码里又不方便提交到私服 具体实施: 首先在项目中增加一个 libs目录,然后把这种非开源又不在私服上的jar包扔进去, 然后打开 ...
- JavaScript DOM 编程艺术(第二版) 常用JS小脚本
function addLoadEvent(func) { var oldonload = window.onload; if (typeof window.onload != 'function') ...