【引入】
每一天都是起床都是新的一天,上午状态好,中午想睡觉,下午渐恢复,加班是煎熬,这都是一种种状态的变化。由此,我们引出一种设计模式,状态模式。
一、状态模式
状态模式(state)当一个对象的内在状态发生变化时线性改变其行为。这个对象看起来像是改变了其类。[DP]
UML类图:
【模式组成】:
- Context上下文类:维护以个具体状态的实例,这个实例维护当前的状态。
- State 抽象状态类:定义一个接口来封装与Context的一个特定状态相关的行为。
- ConcreteState具体状态:每个子类实现一个与Context状态相关的行为。
通用代码:
1、Context:
public class Context {
State s;
public void request() {
s.handle(this);
}
public void setS(State s) {
this.s=s;
}
}
2、State 抽象状态类:
public abstract class State {
public abstract void handle(Context c);
}
3、具体状态类 Concrete1、2、3:
public class ConcreteState1 extends State {
@Override
public void handle(Context c) {
System.out.println("目前状态1,正在转向状态2!");
c.setS(new ConcreteState2());
c.request();
}
}
public class ConcreteState2 extends State {
@Override
public void handle(Context c) {
System.out.println("目前转移到状态2,正在转向状态3!");
c.setS(new ConcreteState3());
c.request();
}
}
public class ConcreteState3 extends State {
@Override
public void handle(Context c) {
System.out.println("已到达状态3,状态转移结束!");
}
}
4、测试类
public class Client {
public static void main(String[] args) {
Context c=new Context();
c.setS(new ConcreteState1());
c.request();
}
}
二、应用举例
展示每一天的不同时段的状态
UML类图:
Work类
public class Work {
private State current;
private double hour;
private boolean finish = false;
public Work() {
this.current = new ForenoonState();
}
public void setCurrent(State current) {
this.current = current;
}
public void setHour(double hour) {
this.hour = hour;
}
public void setFinish(boolean finish) {
this.finish = finish;
}
public State getCurrent() {
return current;
}
public double getHour() {
return hour;
}
public boolean isFinish() {
return finish;
}
public void writeProgram() {
current.writeProgram(this);
}
}
抽象状态类
/**
* 抽象状态
*/
public abstract class State {
public abstract void writeProgram(Work work);
}
具体状态类
/**
* 上午工作状态
*/
public class ForenoonState extends State{
@Override
public void writeProgram(Work work) {
if(work.getHour()<12){
System.out.println("当前时间:"+work.getHour()+"点 上午工作,精神百倍");
}
else {
work.setCurrent(new NoonState());
work.writeProgram();
}
}
}
/**
* 中午工作状态
*/
public class NoonState extends State {
@Override
public void writeProgram(Work work) {
if(work.getHour()<13){
System.out.println("当前时间:"+work.getHour()+"点 饿了,到点该吃饭了");
}
else
{
work.setCurrent(new AfternoonState());
work.writeProgram();
}
}
}
/**
* 下午工作状态
*/
public class AfternoonState extends State{
@Override
public void writeProgram(Work work) {
if(work.getHour()<17){
System.out.println("当前时间:"+work.getHour()+"点 下午状态还不错,继续努力");
}
else {
work.setCurrent(new EveningState());
work.writeProgram();
}
}
}
/**
* 晚间工作状态
*/
public class EveningState extends State {
@Override
public void writeProgram(Work work) {
if (work.isFinish()) {
work.setCurrent(new RestState());
work.writeProgram();
} else {
if (work.getHour() < 21) {
System.out.println("当前时间:" + work.getHour() + "点 还要加班");
} else {
work.setCurrent(new SleepingState());
work.writeProgram();
}
}
}
}
/**
* 睡眠状态
*/
public class SleepingState extends State{
@Override
public void writeProgram(Work work) {
System.out.println("当前时间:"+work.getHour()+"点 太困了,该睡觉了");
}
}
/**
* 下班休息状态
*/
public class RestState extends State{
@Override
public void writeProgram(Work work) {
System.out.println("当前时间:"+work.getHour()+"点 该下班回家了");
}
}
客户端类
public class Client {
public static void main(String[] args) {
Work project=new Work();
project.setHour(9);
project.writeProgram();
project.setHour(12);
project.writeProgram();
project.setHour(13);
project.writeProgram();
project.setHour(17);
project.setFinish(false);
project.writeProgram();
project.setHour(22);
project.writeProgram();
}
}
三、模式优缺点
1、好处
将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。简而言之就是,将特定状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个State实现类中,所以通过定义新的子类可以很容易的增加新的状态和转换。这样做的目的就是为了消除庞大的分支语句,大的分支判断通过会使得它们难以修改和扩展。状态模式通过把各种状态转移逻辑分不到State子类之间,来减少相互间的依赖,这样就容易维护和扩展了。
2、使用场景:
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。
3、缺点:
- 状态模式的使用必然会增加系统类和对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
- 状态模式对”开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
注意:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
四、JDK中的应用
1、javax.faces.webapp.FacesServlet
- 实例方法的执行依赖于实例状态。