定义
- 允许一个对象在其内部状态改变时,改变它的行为。
- 一个对象当他的内部状态改变时,也需要改变他的行为,当然只做状态的互相转换也可以。
- 当控制一个对象状态转变比较复杂的时候,把状态的判断逻辑转移到表示不同状态的一系列类当中。
适用场景
- 一个对象存在多个状态(不同状态下行为不同),且状态可以相互转换。
优点
- 将不同的状态隔离。
- 把各种状态的转换逻辑,分布到State的子类中,减少相互间的依赖。
- 增加新的状态非常简单。
缺点
- 面多业务复杂的场景,导致类数目的增加,系统变复杂。
代码
我们在购物的时候,通常会有这么几个状态
- 待付款状态
- 付款状态
- 等待发货
- 发货状态
- 收货状态
接下来,让我们用代码简单实现一下这个状态转换的过程。
购物状态抽象类(ShoppingState
)
public abstract class ShoppingState {
protected ShoppingContext shoppingContext;
public void setShoppingContext(ShoppingContext shoppingContext) {
this.shoppingContext = shoppingContext;
}
//等待付款
public abstract void waitingPay();
//付款
public abstract void pay();
//等待发货
public abstract void waitingDelivery();
//发货
public abstract void delivery();
//收货
public abstract void receive();
}
抽象类中 除了上述的几个状态方法之外,还有一个 购物上下文(ShoppingContext
),这个就是管理整个状态转换的容器。
购物上下文(ShoppingContext
)
public class ShoppingContext {
private ShoppingState shoppingState;
public final static WaitingPayState WAITING_PAY_STATE = new WaitingPayState();
public final static PayState PAY_STATE = new PayState();
public final static WaitingDeliveryState WAITING_DELIVERY_STATE = new WaitingDeliveryState();
public final static DeliveryState DELIVERY_STATE = new DeliveryState();
public final static ReceiveState RECEIVE_STATE = new ReceiveState();
public ShoppingState getShoppingState() {
return shoppingState;
}
public void setShoppingState(ShoppingState shoppingState) {
this.shoppingState = shoppingState;
this.shoppingState.setShoppingContext(this);
}
public void waitingPay() {
this.shoppingState.waitingPay();
}
public void pay() {
this.shoppingState.pay();
}
public void waitingDelivery() {
this.shoppingState.waitingPay();
}
public void delivery() {
this.shoppingState.delivery();
}
public void receive() {
this.shoppingState.receive();
}
}
购物上下文类中 包含了整个购物流程的实现方法,同时提供了切换上下文状态的方法(setShoppingStatesetShoppingState(ShoppingState shoppingState)
)
具体状态实现类
待付款状态(WaitingPayState
)
public class WaitingPayState extends ShoppingState {
@Override
public void waitingPay() {
System.out.println("等待付款状态.....");
}
@Override
public void pay() {
System.out.println("可以进行付款.....");
super.shoppingContext.setShoppingState(ShoppingContext.PAY_STATE);
}
@Override
public void waitingDelivery() {
System.out.println("请先付款.....");
}
@Override
public void delivery() {
System.out.println("请先付款.....");
}
@Override
public void receive() {
System.out.println("请先付款.....");
}
}
这里由于待付款状态只能切换到支付状态,因此在WaitingPayState
这个类中的pay()
方法中,我们进行了上下文状态切换,其他的方法只能给出提示,必须先进行付款。
以下几个实现类也是如此的逻辑,就不重复解释了。
付款状态(PayState
)
public class PayState extends ShoppingState {
@Override
public void waitingPay() {
System.out.println("已经付款了.....");
}
@Override
public void pay() {
System.out.println("付款状态.....");
}
@Override
public void waitingDelivery() {
System.out.println("等待发货.....");
super.shoppingContext.setShoppingState(ShoppingContext.WAITING_DELIVERY_STATE);
}
@Override
public void delivery() {
System.out.println("等待发货.....");
}
@Override
public void receive() {
System.out.println("等待发货.....");
}
}
等待发货状态(WaitingDeliveryState
)
public class WaitingDeliveryState extends ShoppingState{
@Override
public void waitingPay() {
System.out.println("已经付款.....");
}
@Override
public void pay() {
System.out.println("已经付款.....");
}
@Override
public void waitingDelivery() {
System.out.println("等待发货状态.....");
}
@Override
public void delivery() {
System.out.println("可以发货.....");
super.shoppingContext.setShoppingState(ShoppingContext.DELIVERY_STATE);
}
@Override
public void receive() {
System.out.println("等待发货.....");
}
}
发货状态(DeliveryState
)
public class DeliveryState extends ShoppingState{
@Override
public void waitingPay() {
System.out.println("已经付款.....");
}
@Override
public void pay() {
System.out.println("已经付款.....");
}
@Override
public void waitingDelivery() {
System.out.println("已经发货.....");
}
@Override
public void delivery() {
System.out.println("发货状态.....");
}
@Override
public void receive() {
System.out.println("等待确认收货.....");
super.shoppingContext.setShoppingState(ShoppingContext.RECEIVE_STATE);
}
}
收货状态(ReceiveState
)
public class ReceiveState extends ShoppingState {
@Override
public void waitingPay() {
System.out.println("已经付款.....");
}
@Override
public void pay() {
System.out.println("已经付款.....");
}
@Override
public void waitingDelivery() {
super.shoppingContext.setShoppingState(ShoppingContext.WAITING_DELIVERY_STATE);
}
@Override
public void delivery() {
super.shoppingContext.setShoppingState(ShoppingContext.DELIVERY_STATE);
}
@Override
public void receive() {
System.out.println("等待收货状态.....");
}
}
UML类图
stateUML.jpg我们可以看到在上下文中,组合了所有状态,通过上下,可以进行状态切换。
测试代码
public class StateBootStrap {
public static void main(String[] args) {
ShoppingContext shoppingContext = new ShoppingContext();
shoppingContext.setShoppingState(ShoppingContext.WAITING_PAY_STATE);
shoppingContext.waitingDelivery();
System.out.println("当前状态:"+shoppingContext.getShoppingState().getClass().getSimpleName());
//进行付款
shoppingContext.pay();
System.out.println("当前状态:"+shoppingContext.getShoppingState().getClass().getSimpleName());
//等待发货
shoppingContext.waitingDelivery();
System.out.println("当前状态:"+shoppingContext.getShoppingState().getClass().getSimpleName());
//发货
shoppingContext.delivery();
System.out.println("当前状态:"+shoppingContext.getShoppingState().getClass().getSimpleName());
//收货
shoppingContext.receive();
System.out.println("当前状态:"+shoppingContext.getShoppingState().getClass().getSimpleName());
}
}
测试结果
stateResult.jpg在这里我们可以做一个小改动,当我们在收货状态的时候,再次付款时,会发生什么样的输出呢,我们在上面代码中添加一段代码
shoppingContext.pay();
我们来看一下结果
stateResult1.jpg给出了已经付款的提示。
小结
因为状态模式大部分是在业务场景中使用的,因此开源框架中,极少有相关的实现,希望大家结合实际业务去选择合适的设计模式。不要重度设计。
网友评论