一、状态模式介绍
1. 解决的问题
主要解决在对象一个内部状态发生变化时,改变其行为的问题。
2. 定义
状态模式是一种行为设计模式,让你能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。
3. 应用场景
- 如果对象需要根据自身当前状态进行不同行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可使用状态模式。
- 如果某个类需要根据成员变量的当前值改变自身行为,从而需要使用大量的条件语句时,可使用状态模式。
- 当相似状态和基于条件的状态机转换中存在许多重复代码时,可使用状态模式。
二、状态模式优缺点
1. 优点
- 单一职责原则:将与特点状态相关的代码放在单独的类中。
- 开闭原则:无需修改已有状态类和上下文就能引入新状态。
- 通过消除臃肿的状态机条件语句简化上下文代码。
2. 缺点
- 如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大做。
三、状态模式应用实例:简单高效的时间管理——番茄工作法
1. 实例场景
不知道大家有没有经常想认真学习,却一直晚会再说的情况,我反正就是。
最近发现了个番茄工作法,找了个软件体验了一下,听着滴答滴答的工作背景音效,还是很有种时间在哗啦哗啦流的紧迫感,能一定程度上提高点效率,当然可能听习惯了就不当回事了。
具体的软件如果想要的话,评论留言告诉我。
番茄工作法是弗朗西斯科·西里洛在 1922 年创建的一种时间管理方法,有助于提高工作效率,养成良好的学习习惯。
它的基本原理就是把工作时间分为多个番茄钟,一个番茄钟由 25 分钟工作时间和 5 分钟休息时间组成。
- 25 分钟的工作时间内,要保持专注,避免干扰。
5 分钟的休息时间建议离开工作区域,喝一杯茶,做一些简单的伸展运动。
这样看是不是还有点护眼,让我们这些天天对着电脑的农民工能及时想起来自己的眼睛需要休息。
很多时候,感觉忙了一天,也不知道自己在忙啥,也可以用番茄工作法将自己的一天记录下来,分析一下时间都去哪了?
今天,就以番茄工作法的工作状态到休息状态为例,介绍一下状态模式。
2. 状态模式实现
2.1 工程结构
state-pattern
└─ src
├─ main
│ └─ java
│ └─ org.design.pattern.state
│ ├─ model
│ │ ├─ PomodoroState.java
│ │ └─ impl
│ │ ├─ WorkPomodoroState.java
│ │ └─ RestPomodoroState.java
│ └─ service
│ ├─ PomodoroService.java
│ └─ impl
│ └─ PomodoroServiceImpl.java
└─ test
└─ java
└─ org.design.pattern.state.test
└─ PomodoroTest.java
2.2 代码实现
2.2.1 实体类
番茄状态接口
/**
* 番茄状态接口
*/
public interface PomodoroState {
/**
* 工作
*/
void work();
/**
* 休息
*/
void rest();
}
番茄-工作状态类
/**
* 番茄-工作状态类
*/
@Slf4j
public class WorkPomodoroState implements PomodoroState {
/**
* 工作
*/
@Override
public void work() {
log.info("工作中:请保持高度集中!");
}
/**
* 休息
*/
@Override
public void rest() {
log.info("工作状态中断:该番茄钟作废!");
}
}
番茄-休息状态类
/**
* 番茄-休息状态类
*/
@Slf4j
public class RestPomodoroState implements PomodoroState {
/**
* 工作
*/
@Override
public void work() {
log.info("良好的休息才是下一个番茄钟开始的必要条件!");
}
/**
* 休息
*/
@Override
public void rest() {
log.info("工作时间结束了,喝杯水,伸个懒腰,看看窗外!");
}
}
2.2.2 服务类
番茄工作法服务接口
/**
* 番茄工作法服务接口
*/
public interface PomodoroService {
/**
* 开启番茄
*/
void openPomodoro();
}
番茄工作法服务实现类
/**
* 番茄工作法服务实现类
*/
@Slf4j
public class PomodoroServiceImpl implements PomodoroService {
/**
* 开启一次番茄
*/
@Override
public void openPomodoro() {
// 番茄-工作时间
PomodoroState workState = new WorkPomodoroState();
log.info("开启一次番茄时间");
workState.work();
log.info("工作时间想休息");
workState.rest();
log.info("工作时间结束");
// 番茄-休息时间
PomodoroState restState = new RestPomodoroState();
restState.rest();
log.info("休息时间想工作");
restState.work();
log.info("休息时间结束,准备好开始下一个番茄了嘛?");
}
}
2.3 测试验证
2.3.1 测试验证类
/**
* 番茄工作法测试类
*/
public class PomodoroTest {
@Test
public void test() {
PomodoroService pomodoroService = new PomodoroServiceImpl();
pomodoroService.openPomodoro();
}
}
2.3.2 测试结果
15:07:06.447 [main] INFO o.d.p.s.s.impl.PomodoroServiceImpl - 开启一次番茄时间
15:07:06.449 [main] INFO o.d.p.s.model.impl.WorkPomodoroState - 工作中:请保持高度集中!
15:07:06.449 [main] INFO o.d.p.s.s.impl.PomodoroServiceImpl - 工作时间想休息
15:07:06.449 [main] INFO o.d.p.s.model.impl.WorkPomodoroState - 工作状态中断:该番茄钟作废!
15:07:06.449 [main] INFO o.d.p.s.s.impl.PomodoroServiceImpl - 工作时间结束
15:07:06.449 [main] INFO o.d.p.s.model.impl.RestPomodoroState - 工作时间结束了,喝杯水,伸个懒腰,看看窗外!
15:07:06.449 [main] INFO o.d.p.s.s.impl.PomodoroServiceImpl - 休息时间想工作
15:07:06.449 [main] INFO o.d.p.s.model.impl.RestPomodoroState - 良好的休息才是下一个番茄钟开始的必要条件!
15:07:06.449 [main] INFO o.d.p.s.s.impl.PomodoroServiceImpl - 休息时间结束,准备好开始下一个番茄了嘛?
Process finished with exit code 0
四、状态模式结构
- 上下文(Context)保存了对于一个具体状态对象的引用,并会将所有与该状态相关的工作委派给它。上下文通过状态接口与状态对象交互,且会提供一个设置器用于传递新的状态对象。
- 状态(State)接口会声明特定于状态的方法,这些方法应能被其他所有具体状态所理解。
具体状态(Concrete States)会自行实现特定于状态的方法。为了避免多个状态中包含相似代码,可以提供一个封装有部分通用行为的中间抽象类。
状态对象可存储对于上下文对象的反向引用。状态可以通过该引用从上下文处获取所需信息,并且能触发状态转移。
- 上下文和具体状态都可以设置上下文的下个状态,并可通过替换连接到上下文的状态对象来完成实际的状态转换。
设计模式并不难学,其本身就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深入设计模式:https://refactoringguru.cn/design-patterns/catalog
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。