1. 状态设计模式介绍
很多情况下,一个对象的行为取决于它的一个或者多个变化的属性,这些属性我们称之为状态,这个对象称为状态对象。对于状态对象而言,它的行为依赖于它的状态。
举个例子: 我们买火车票,只有我们买票了之后,才会有退票这个选项。没有买票则没有退票的选项。所以说我们退票的行为依赖于我们已经买票了这个”状态”。
状态模式和策略模式的结构很相似,但是它们的目的和本质上却不是一样的。
状态模式是平行的,不可替换的;策略模式是彼此独立的,可相互替换的。怎么理解这句话呢?
举个例子,策略设计模式就好比我们到达一个目的地有多种策略,坐汽车,坐火车,坐飞机。这三个方案之间是相互独立,互不影响的,并且是相互替换的。
状态模式拿刚刚那个买票的例子,已经买票和退票这两个行为是平行的,它们之间是有联系的。并且这两个状态是不可以相互替换的。
2. 状态设计模式使用场景
- 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 代码中包含大量与状态对象有关的条件语句。(if-else)
3. 状态设计模式的UML类图
4. 状态设计模式的实现
情景如下: 我们都有买过火车票的经历,没有下单之前,查询订单信息,退款功能是没有的。下单之后,下单是没有的,因为不可以下同一单(单号相同)。
- 如果我们采用传统的if-else,代码如下:
public class Client {
private final static int BEFORE_ORDERED = 0;
private final static int AFTER_ORDERED = 1;
private int mState = 0;
public static void main(String[] args) {
Client client = new Client();
//下单之前
client.setOrderState(BEFORE_ORDERED);
client.order();
client.queryInfo();
client.refund();
System.out.println("--------");
client.setOrderState(AFTER_ORDERED);
client.order();
client.queryInfo();
client.refund();
}
//设置订单状态
public void setOrderState(int orderState) {
this.mState = orderState;
}
//下单
public void order() {
if (mState == BEFORE_ORDERED) {
System.out.println("下单了");
}
}
//查询订单详情
public void queryInfo() {
if (mState == AFTER_ORDERED) {
System.out.println("订单详情");
}
}
//退款
public void refund() {
if (mState == AFTER_ORDERED) {
System.out.println("退款了");
}
}
}
采用传统的if-else,我们发现每次都要变换写if-else的条件,稍有不慎就可能写错。如果条件更为复杂,代码将更加冗余繁杂。
下面我们来看看采用状态设计模式之后的代码:
包结构如下:
(1) 首先定义一个接订单状态的接口:
public interface OrderState {
//下单
public void order();
//查看订单状态
public void queryInfo();
//退款
public void refund();
}
(2)接下来定义“下单之前”的状态类和下单之后的状态类,两个都实现这个接口
下单之前的状态类:
public class BeforeOrdered implements OrderState {
@Override
public void order() {
System.out.println("下单了");
}
@Override
public void queryInfo() {
//无法查询到任何信息,当前还没有订单
}
@Override
public void refund() {
//无法退款,当前还没有任何订单
}
}
下单之前只有order()方法实现了具体方法,因为其他两个再当前状态下无法执行。
下单之后的状态类:
public class AfterOrdered implements OrderState {
@Override
public void order() {
//已经下单后,不能重复下同一单
}
@Override
public void queryInfo() {
System.out.println("正在查询订单信息");
}
@Override
public void refund() {
System.out.println("正在退款");
}
}
下单后的状态类中,实现了后面两个方法,因为在“下单后”的状态下,不能重复下同一个订单,所以order()方法没有实现。
(3) 接下来我们来定义一个状态控制类:
public class OrderStateController implements OrderState{
private OrderState orderState;
public void setOrderState(OrderState orderState) {
this.orderState = orderState;
}
@Override
public void order() {
orderState.order();
}
@Override
public void queryInfo() {
orderState.queryInfo();
}
@Override
public void refund() {
orderState.refund();
}
}
在OrderStateController这个类中,通过 setOrderState()方法设置不同的状态。
然后实现OrderState接口中的三个方法,而具体调用的是通过setOrderState()设置的状态类里面对应的方法。
(4) 测试类:
public class Client {
public static void main(String[] args) {
OrderStateController orderStateController = new OrderStateController();
//状态:下单之前
orderStateController.setOrderState(new BeforeOrdered());
//下单之前下单
orderStateController.order();
//下单之前查询
orderStateController.queryInfo();
//下单之前退款
orderStateController.refund();
System.out.println("---------------");
//改变状态,下单了
orderStateController.setOrderState(new AfterOrdered());
//下单之后,下单
orderStateController.order();
//下单之后查询
orderStateController.queryInfo();
//下单之后退款
orderStateController.refund();
}
}
结果如下:
5. 状态设计模式在Android源码中
在Android源码中,WIFI管理是一个典型的状态模式。
当我们点击扫描WIFI时,不同的状态对于扫描WIFI这个请求的处理方式是不一样的。
- 在初始状态下: 扫描请求直接被忽略。
- 在驱动加载状态下: WIFI扫描请求被添加到延迟处理的消息队列。
- 在驱动加载完成状态下: 扫描WIFI的请求直接被处理。
6. 状态设计模式在Android开发中
状态模式在Android中的开发,其实就是在Java中开发。一般只要用到if-else的地方,都能够用到状态模式。
比如登录和注销两种状态模式下,相同的操作会有不同的结果。
比如我们打开一个新安装的应用,注销状态下,评论操作直接跳转到登录界面。而在登录状态下,就可以跳转评论的操作界面。
其实不论是在Android下还是Java,状态模式的关键点在于不同的状态下对于同一行为有不同的响应,这其实就是一个将if-else用多态来实现的一个具体实例。
7. 总结
- 优点:
- 将特定状态下的行为封装,是不同状态下的行为独立起来,减少相互依赖。
- 减少多余繁琐的状态判断。
- 缺点:
- 使类的数目增加。