当一个对象在内在状态改变时,允许改变起行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
简例
工作状态-分类板
package com.example.designmode.statepattern;
import lombok.Data;
/**
* design-mode
* 工作状态-分类板
*
* @author : ZhangYuJie
* @date : 2022-04-24 14:56
**/
@Data
public class Work {
private int hour;
private Boolean finish=false;
public void writeProgram() {
if (hour < 12) {
System.err.println("当前时间:上午" + hour + "点");
} else if (hour < 13) {
System.err.println("当前时间:中午" + hour + "点");
} else if (hour < 17) {
System.err.println("当前时间:下午" + hour + "点");
} else {
if (finish) {
System.err.println("当前时间:下班回家" + hour + "点");
} else {
if (hour < 21) {
System.err.println("当前时间:加班哦,疲累之极" + hour + "点");
} else {
System.err.println("当前时间:不行了,睡着了" + hour + "点");
}
}
}
}
}
客户端程序:
public static void main(String[] args) {
Work emergencyProjects = new Work();
emergencyProjects.hour = 9;
emergencyProjects.writeProgram();
emergencyProjects.hour = 10;
emergencyProjects.writeProgram();
emergencyProjects.hour = 12;
emergencyProjects.writeProgram();
emergencyProjects.hour = 13;
emergencyProjects.writeProgram();
emergencyProjects.hour = 14;
emergencyProjects.writeProgram();
emergencyProjects.hour = 17;
emergencyProjects.writeProgram();
//emergencyProjects.WorkFinished = true;
emergencyProjects.finish = false;
emergencyProjects.writeProgram();
emergencyProjects.hour = 19;
emergencyProjects.writeProgram();
emergencyProjects.hour = 22;
emergencyProjects.writeProgram();
}
以上代码有个很大的问题:
‘Work’类的’writeProgram’方法很长,而且有很多判断的分支,这也就意味着它的责任过大了。无论是任何状态,都需要通过它来改变,这实际上是很糟糕的。
面对对象设计其实就是希望做到代码的责任分解这个类违背了’单一职责原则’。而且由于’WriteProgram’的方法里面有这么多判断,使得任何需求的改动或增加,都需要更改这个方法。又违背了’开放-封闭原则’。这类有个解决方案,就是’状态模式’。
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于摸个ConcreteState中,所以通过定义新的字类可以很容易地增加新的状态与转换。这样做的目的就是为了消除庞大的条件分支语句。状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以使用状态模式了。
工作状态-状态模式板
package com.example.designmode.statepattern;
/**
* design-mode
* 抽象状态
*
* @author : ZhangYuJie
* @date : 2022-04-24 15:14
**/
public abstract class State {
public abstract void writeProgram(Work w);
}
上午工作状态
package com.example.designmode.statepattern;
/**
* design-mode
* 上午工作状态
*
* @author : ZhangYuJie
* @date : 2022-04-24 15:14
**/
public class ForenoonState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 12)
{
System.err.println("当前时间:上午"+w.getHour()+"点");
} else
{
w.setState(new NoonState());
w.writeProgram();
}
}
}
中午工作状态
package com.example.designmode.statepattern;
/**
* design-mode
* 中午工作状态
*
* @author : ZhangYuJie
* @date : 2022-04-24 15:17
**/
public class NoonState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 13)
{
System.err.println("当前时间: 下午"+w.getHour()+"点");
} else
{
w.setState(new EveningState());
w.writeProgram();
}
}
}
下午工作状态
package com.example.designmode.statepattern;
/**
* design-mode
*
*
* @author : ZhangYuJie
* @date : 2022-04-24 15:36
**/
public class AfterNoonState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 13) {
System.err.println("当前时间:下午" + w.getHour() + "点");
} else {
w.setState(new EveningState());
w.writeProgram();
}
}
}
晚间工作状态
package com.example.designmode.statepattern;
/**
* design-mode
* 晚间工作状态
*
* @author : ZhangYuJie
* @date : 2022-04-24 15:18
**/
public class EveningState extends State {
@Override
public void writeProgram(Work w) {
if (w.getFinish())
{
w.setState(new RestState());
w.writeProgram();
} else
{
if (w.getHour() < 21)
{
System.err.println("当前时间:加班哦,疲累"+w.getHour()+"点");
} else
{
w.setState(new SleepingState());
w.writeProgram();
}
}
}
}
睡眠状态
package com.example.designmode.statepattern;
/**
* design-mode
* 睡眠状态
*
* @author : ZhangYuJie
* @date : 2022-04-24 15:20
**/
public class SleepingState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 13) {
System.err.println("当前时间: 不行了,睡着了。" + w.getHour() + "点");
}
}
}
下班休息状态
package com.example.designmode.statepattern;
/**
* design-mode
* 下班休息状态
*
* @author : ZhangYuJie
* @date : 2022-04-24 15:21
**/
public class RestState extends State {
@Override
public void writeProgram(Work w) {
System.err.println("当前时间: 下班回家了。"+w.getHour()+"点");
}
}
工作类改造
package com.example.designmode.statepattern;
import lombok.Data;
/**
* design-mode
* 工作状态-改造版
*
* @author : ZhangYuJie
* @date : 2022-04-24 14:56
**/
@Data
public class Work {
private int hour;
private Boolean finish = false;
private State state;
public Work() {
state = new ForenoonState();
}
public void writeProgram() {
this.state.writeProgram(this);
}
}
客户端代码,没有任何改动。但我们的程序却更加灵活易变了。
public static void main(String[] args) {
Work emergencyProjects = new Work();
emergencyProjects.hour = 9;
emergencyProjects.writeProgram();
emergencyProjects.hour = 10;
emergencyProjects.writeProgram();
emergencyProjects.hour = 12;
emergencyProjects.writeProgram();
emergencyProjects.hour = 13;
emergencyProjects.writeProgram();
emergencyProjects.hour = 14;
emergencyProjects.writeProgram();
emergencyProjects.hour = 17;
emergencyProjects.writeProgram();
//emergencyProjects.WorkFinished = true;
emergencyProjects.finish = true;
emergencyProjects.writeProgram();
emergencyProjects.hour = 19;
emergencyProjects.writeProgram();
emergencyProjects.hour = 22;
emergencyProjects.writeProgram();
}
状态模式总结
状态模式的主要优点在于封装了转换规则,并枚举可能的状态,它将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为,还可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;其缺点在于使用状态模式会增加系统类和对象的个数,且状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,对于可以切换状态的状态模式不满足“开闭原则”的要求