设计模式之状态模式
程序员文章站
2024-03-24 19:24:58
...
前言:
状态模式(State Pattern)当一个对象的内在状态改变时,允许改变其行为。这个对象看起来像是改变了其类。
一.状态模式简介
状态模式(State Pattern)解决的是当控制一个对象状态的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,把复杂的判断逻辑简化了。
二.状态模式的实例讲解
案例:对一个人一天各个时刻的工作状态进行判断,根据状态改变工作行为。
1.产品设计UML类图
(图片加载慢,多刷新几下,耐心等待……)
注:工作状态类Work
和状态抽象类State
是聚合关系,State
包含WORK
,但不是WORK
的一部分。
聚合关系:表示一种弱的"拥有"关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分。
2.状态抽象类
设计分析:定义一个接口,封装与工作状态类(Work类
)的一个特定状态相关的行为(doSomeWork()
)。
package com.pattern.state.state;
import com.pattern.state.context.Work;
/**
* 状态抽象类
*/
public abstract class State {
public abstract void doSomeWork(Work work);
}
3.具体状态类
设计分析: 每个子类都实现一个与工作状态(Work
)的一个状态相关的行为,这样做的目的是把各种状态的转移逻辑分布到State
子类之间,来减少相互间的依赖。
在本例中,上午工作状态、下午工作状态、晚上工作状态、睡觉休息状态都继承自State
抽象类,并实现与工作状态相关的行为(doSomeWork()
方法)。
①上午工作状态类
package com.pattern.state.state;
import com.pattern.state.context.Work;
/**
* 上午状态
*/
public class AMState extends State {
@Override
public void doSomeWork(Work work) {
if (work.getHour()<12) {
System.out.println("上午"+work.getHour()+"点钟,努力工作中……");
}else {
work.setState(new PMState());
work.doSomeWork();
}
}
}
②下午工作状态类
package com.pattern.state.state;
import com.pattern.state.context.Work;
/**
* 下午状态
*/
public class PMState extends State {
@Override
public void doSomeWork(Work work) {
if (work.getHour()<18) {
System.out.println("下午"+work.getHour()+"点钟,团队开会……");
}else {
work.setState(new NightState());
work.doSomeWork();
}
}
}
③晚上工作状态类
package com.pattern.state.state;
import com.pattern.state.context.Work;
/**
* 晚上状态
*/
public class NightState extends State {
@Override
public void doSomeWork(Work work) {
if (work.isFinish()) {
work.setState(new EndWorkState());
work.doSomeWork();
}else if (work.getHour()<23) {
System.out.println(work.getHour()+"点钟,加班中……");
}else if (work.getHour()>23){
work.setState(new SleepState());
work.doSomeWork();
}
}
}
④停止工作状态类
package com.pattern.state.state;
import com.pattern.state.context.Work;
/**
* 结束工作状态
*/
public class EndWorkState extends State {
@Override
public void doSomeWork(Work work) {
if (work.getHour()>23) {
work.setState(new SleepState());
work.doSomeWork();
}else {
System.out.println(work.getHour()+"点钟,工作完成了,终于下班了");
}
}
}
⑤休息睡觉状态类
package com.pattern.state.state;
import com.pattern.state.context.Work;
/**
* 睡觉休息状态
*/
public class SleepState extends State {
@Override
public void doSomeWork(Work work) {
System.out.println("晚上"+work.getHour()+"点钟,睡觉吧");
}
}
4.工作状态类
设计分析: 维护一个State
对象的具体实例,用于封装所有工作状态相关的代码。
package com.pattern.state.context;
import com.pattern.state.state.AMState;
import com.pattern.state.state.State;
/**
* 工作状态
*/
public class Work {
private State current;
private double hour;// 判断状态变化的标准
private boolean finish = false;// 工作完成的标志位
public Work() {
// 初始化为上午状态,从上午开始工作,定义当前状态
this.current = new AMState();
}
public double getHour() {
return hour;
}
public void setHour(double hour) {
this.hour = hour;
}
public boolean isFinish() {
return finish;
}
public void setFinish(boolean finish) {
this.finish = finish;
}
public void doSomeWork() {
current.doSomeWork(this);
}
public void setState(State s) {
current = s;
}
}
5.客户端中使用
package com.pattern.state.client;
import com.pattern.state.context.Work;
public class Client {
public static void main(String[] args) {
//创建状态对象
Work work =new Work();
//设置状态变化的标志
work.setHour(9);
//执行状态相关的行为
work.doSomeWork();
work.setHour(14);
work.doSomeWork();
work.setHour(18);
work.doSomeWork();
work.setHour(21);
//完成工作了,设为true,默认为false
work.setFinish(true);
work.doSomeWork();
work.setHour(24);
work.doSomeWork();
}
}
6.运行结果展示
在工作没有做完(work.setFinish(false)
)的情况下:
上午9.0点钟,努力工作中……
下午14.0点钟,团队开会……
18.0点钟,加班中……
21.0点钟,加班中……
晚上24.0点钟,睡觉吧
在工作做完(work.setFinish(true)
)的情况下:
上午9.0点钟,努力工作中……
下午14.0点钟,团队开会……
18.0点钟,加班中……
21.0点钟,工作完成了,终于下班了
晚上24.0点钟,睡觉吧
7.源码下载
本文示例代码下载地址:点击下载
三.总结:
当一个对象的行为取决于它的状态,并且需要在运行中根据状态改变它的行为的时候,就可以考虑使用状态模式了,状态模式是条件分支语句的代替者。
1.状态模式的优点
- 封装了转换的规则
- 将可能的状态分解到状态子类中,解除了各种状态之间的耦合,便于修改和扩展。
- 状态逻辑和状态对象整合在一起,替代了庞大的条件语句块
2.状态模式的缺点
- 增加类和对象的个数。
- 对
开放-封闭
原则支持不太好,当新增状态类的时候,需要修改负责状态转换的源码;修改状态类行为的时候,也要修改对应类的源码。