状态在我们的生活中是很常见的,比如我们交通使用的红绿信号灯,有红、黄、绿三种状态。其实我们的衣食住行都是状态,比如火车的启动,运行,暂停,状态几乎是无处不在。下面我们来看一个大家再熟悉不过的状态图
想必大家也都知道这几种状态的意义了。其实在我们程序里面状态也是很常见的,比如我们经常使用的switch语句就是最好的说明,case后面的值就是我们所说的状态值,线程的五种状态:新建状态、就绪状态、运行状态、阻塞状态、死亡状态。
言归正传!!!状态模式就是允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
状态模式的使用性:
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.代码中包含大量与对象状态有关的条件语句:一个操作中含有庞大的多分支的条件(if else(或switch case)语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常 , 有多个操作包含这一相同的条件结构。 状态模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
状态模式的参与者:
环境类 : 定义一个接口。维护一个具体状态子类的实例,这个实例定义当前状态。
抽象状态类: 定义一个接口以封装与环境类的一个特定状态相关的行为。
具体状态类: 每一子类实现一个与环境类的一个状态相关的行为。
以购物里面的搜索商品,下订单、正在配送中、确认收货、订单评价这五个状态为例
抽象状态类ShoppingState.class
/**
* 抽象状态类
*/
public interface ShoppingState {
void handleState(Shopping shopping);
String getState();
}
环境类Shopping.class
/**
* 环境类
*/
public class Shopping {
ShoppingState state;
public void setState(ShoppingState state) {
this.state = state;
}
public void handle(){
state.handleState(this);
}
}
具体状态类SearchGoods.class
/**
* 搜索商品的状态
*/
public class SearchGoods implements ShoppingState{
@Override
public void handleState(Shopping shopping) {
System.out.println(this.getState());
ShoppingState state = new PlaceOrder();
shopping.setState(state);
state.handleState(shopping);
}
@Override
public String getState() {
return "搜索商品已经完成!!!";
}
}
具体状态类PlaceOrder.class
/**
* 下订单的状态
*/
public class PlaceOrder implements ShoppingState{
@Override
public void handleState(Shopping shopping) {
System.out.println(this.getState());
ShoppingState state = new Distribution();
shopping.setState(state);
state.handleState(shopping);
}
@Override
public String getState() {
return "下订单已经完成!!!";
}
}
具体状态类Distribution.class
/**
* 商品配送的状态
*/
public class Distribution implements ShoppingState{
@Override
public void handleState(Shopping shopping) {
System.out.println(this.getState());
ShoppingState state = new Receipt();
shopping.setState(state);
state.handleState(shopping);
}
@Override
public String getState() {
return "商品配送已经完成!!!";
}
}
具体状态类Receipt.class
/**
* 商品接收的状态
*/
public class Receipt implements ShoppingState{
@Override
public void handleState(Shopping shopping) {
System.out.println(this.getState());
ShoppingState state = new Evaluate();
shopping.setState(state);
state.handleState(shopping);
}
@Override
public String getState() {
return "商品接收已经完成!!!";
}
}
具体状态类Evaluate.class
/**
* 评价的状态
*/
public class Evaluate implements ShoppingState{
@Override
public void handleState(Shopping shopping) {
System.out.println(this.getState());
System.out.println("~~~~~~~~到此已经走完整个流程了~~~~~~~~");
}
@Override
public String getState() {
return "评价已经完成!!!";
}
}
测试代码
Shopping shopping = new Shopping();
shopping.setState(new SearchGoods());
shopping.handle();
运行效果图
通过上面的代码我们可以很明显的看出状态模式的优缺点
优点:
封装了转换规则。
将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
状态模式的使用必然会增加系统类和对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
状态模式的介绍就到此为止了,如有疑问欢迎留言。