状态模式中的行为是由状态来决定的,不同的状态下有不同的行为。状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。意图是让一个对象在其内部状态改变的时候,行为也随之改变。

##使用场景

1. 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为
2. 代码中包含大量与对象状态有关的条件语句,例如if-else, switch-case且这些分支依赖于该对象的状态

状态模式将每一个条件分支放入一个独立的类中,这使得你可以根据对象自身的情况将对象的状态作为一个对象,通过多态来去除过多的if-else

实现
-
下面代码主要是实现一个简单的例子,根据人不同的状态(坐着或躺着)来进行不同的动作,其实也就是一个简单的多态实现。
创建接口

1
2
3
4
5
6
7
8
public interface HumanState {

// 人坐着时吃饭
public void eat();

// 人躺着时睡觉
public void sleep();
}

实现坐着时的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public class HumanSit implements HumanState{

@Override
public void eat() {
System.out.println("开始吃饭");
}

@Override
public void sleep() {
// 不做任何操作或者是提示用户当前状态不符
System.out.println("我在吃饭,不能睡觉");
}
}

实现躺着时的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public class HumanLie implements HumanState{

@Override
public void eat() {
// 不做任何操作或者提示用户状态不符
System.out.println("我在睡觉,不能吃饭");
}

@Override
public void sleep() {
System.out.println("开始睡觉");
}
}

创建改变状态接口

1
2
3
4
public interface HumanStateControl {
public void changeIntoSit();
public void changeIntoLie();
}

创建控制人物行为的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class HumanControl implements HumanStateControl{
// 人默认是坐着的
HumanState humanState = new HumanSit();

public void setHumanState(HumanState humanState) {
this.humanState = humanState;
}

@Override
public void changeIntoSit() {
setHumanState(new HumanSit());
System.out.println("坐起来啦");
}

@Override
public void changeIntoLie() {
setHumanState(new HumanLie());
System.out.println("躺下啦");
}

public void eat(){
humanState.eat();
}

public void sleep(){
humanState.sleep();
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestModule {

public static void main(String[] args) {
HumanControl humanControl = new HumanControl();

humanControl.changeIntoSit();
humanControl.eat();
humanControl.sleep();

humanControl.changeIntoLie();
humanControl.eat();
humanControl.sleep();
}
}

由于结果是很显而易见的,这里就不贴出来了。
而从上面的流程来看,对于一个小的项目来说,这样的操作确实很繁琐,因为要编写很多的接口以及相关的controller类,但是对于一个中型或者是大型的需要考虑维护性和拓展性的项目来说,这种方式在编写的时候就简洁多了。如果不使用状态模式,那么我们在TestModule的Main方法中就必须要添加一大堆的if-else条件判断,少量的还好,但是如果一旦判断过多,以后维护和拓展时是要死人的。

实用场景
-
Android中一个很典型的使用了状态模式的地方就是Wifi管理。具体的可以看一下它的源码,内容有点多,就不赘述了,这里只是简单分析一下大概:
在wifi管理的状态中,状态存在一个层级关系,树型的,当前状态只能转换上一个状态或者是下一个状态,不能够跨越转换,这里面存在一个状态转换规则。从这里面我们也可以学习到,以后自己编的时候也可以注意一下状态的转换关系,根据项目的需要判断是否可以跨越式转换,如果不可以的话,就一定要制定好相应的状态转换规则。

##总结

状态模式其实还是挺常用的,根据用户的状态去产生不同的用户行为,代码可维护性和可拓展性都大大的提升,也避免的代码的膨胀(if-else等)。
缺点也倒是听明显的,对于一些小的项目来说,用处不是特别大,因为状态模式肯定会增加系统类和对象的个数