介绍
状态模式和策略模式是一对双胞胎,他们都属于行为设计模式。状态模式和策略模式都是为具有多种可能情形设计的模式,把不同的处理情形抽象为一个相同的接口,符合对扩展开放,对修改封闭的原则。策略模式封装了一组相关算法,它允许Client在运行时使用可互换的行为;状态模式帮助一个类在不同的状态显示不同的行为。状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。
状态模式(State Pattern) 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
TCP协议中的三次握手和四次断开也可以使用状态模式来实现。
结构图
时序图
案例
我就用工作日的上班时间来举例子
6种状态
- 23点到早上7点
- 7点到9点
- 9点到12点
- 12点到13点
- 13点到18点
- 18点到23点
State 抽象类
public abstract class State {
public abstract void handle(WorkDay workDay);
public void changeState(WorkDay workDay){
State state = null;
if (23 < workDay.getHour() || workDay.getHour() <= 7) {
state = new SleepState();
}
if (7 < workDay.getHour() && workDay.getHour() <= 9) {
state = new EarlyMorningState();
}
if (9 < workDay.getHour() && workDay.getHour() <= 12) {
state = new MorningState();
}
if (12 < workDay.getHour() && workDay.getHour() <= 13) {
state = new MiddayState();
}
if (13 < workDay.getHour() && workDay.getHour() < 18) {
state = new AfternoonState();
}
if (18 < workDay.getHour() && workDay.getHour() <= 23) {
state = new NightState();
}
workDay.setState(state);
workDay.doWork();
}
}
23点到早上7点睡觉状态SleepState
public class SleepState extends State {
@Override
public void handle(WorkDay workDay) {
if (23 < workDay.getHour() || workDay.getHour() <= 7) {
System.out.println("现在是" + workDay.getHour() + "点,晚上睡觉时间!");
} else {
changeState(workDay);
}
}
}
**7点到9点清晨状态EarlyMorningState **
public class EarlyMorningState extends State {
@Override
public void handle(WorkDay workDay) {
if (7 < workDay.getHour() && workDay.getHour() <= 9) {
System.out.println("现在是" + workDay.getHour() + "点,清晨,准备上班!");
} else {
changeState(workDay);
}
}
}
9点到12点上午上班状态MorningState
public class MorningState extends State{
@Override
public void handle(WorkDay workDay) {
if (9 < workDay.getHour() && workDay.getHour() <= 12) {
System.out.println("现在是" + workDay.getHour() + "点,上午工作时间!");
} else {
changeState(workDay);
}
}
}
12点到13点中午休息状态MiddayState
public class MiddayState extends State {
@Override
public void handle(WorkDay workDay) {
if (12 < workDay.getHour() && workDay.getHour() <= 13) {
System.out.println("现在是"+workDay.getHour()+"点,中午休息时间!");
} else {
workDay.setState(new NightState());
workDay.doWork();
}
}
}
13点到18点下午工作状态AfternoonState
public class AfternoonState extends State {
@Override
public void handle(WorkDay workDay) {
if (13 < workDay.getHour() && workDay.getHour() <= 18) {
System.out.println("现在是" + workDay.getHour() + "点,下午工作时间!");
} else {
changeState(workDay);
}
}
}
18点到23点晚上下班状态NightState
public class NightState extends State {
@Override
public void handle(WorkDay workDay) {
if (18 < workDay.getHour() && workDay.getHour() <= 23) {
System.out.println("现在是" + workDay.getHour() + "点,晚上下班时间!");
} else {
changeState(workDay);
}
}
}
工作日类WorkDay
public class WorkDay {
private State state = new NightState();
private int hour;
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public void doWork(){
state.handle(this);
}
}
调用类Client
public class Client {
public static void main(String[] args) {
WorkDay workDay = new WorkDay();
for (int i = 0; i < 55; i++) {
workDay.setHour(i%24);
workDay.doWork();
}
}
}
运行结果
总结
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
环境类实际上就是拥有状态的对象,环境类有时候可以充当状态管理器(State Manager)的角色,可以在环境类中对状态进行切换操作。
抽象状态类可以是抽象类,也可以是接口,不同状态类就是继承这个父类的不同子类,状态类的产生是由于环境类存在多个状态,同时还满足两个条件: 这些状态经常需要切换,在不同的状态下对象的行为不同。因此可以将不同对象下的行为单独提取出来封装在具体的状态类中,使得环境类对象在其内部状态改变时可以改变它的行为,对象看起来似乎修改了它的类,而实际上是由于切换到不同的具体状态类实现的。由于环境类可以设置为任一具体状态类,因此它针对抽象状态类进行编程,在程序运行时可以将任一具体状态类的对象设置到环境类中,从而使得环境类可以改变内部状态,并且改变行为。