
业务场景
学过设计模式的兄弟们一定经常在写代码的时候思索, 倒底何时才能使用我的洪荒之力呢?
笔者最近恰好就遇到了最合适不过的需求, 简单介绍下:
- 需要一直对设备进行监控
- 可以对设备发送向上移动/向下移动/停止移动指令
- 设备离线时, 需要重连并进行初始化
- 设备初始化过程中, 需要获取设备情况
- 设备正常运行时, 需要获取设备坐标
方案
按照上面的需求, 我们很容易写出如下结构的代码:
if (device.getStatus() == Device.Status.OFFLINE) {
// 业务代码
} else if (device.getStatus() == Device.Status.INIT) {
// 业务代码
}
...
复制代码
乍一看逻辑非常严谨, 但实际情况是, 在向上移动的方法中, 会出现这一堆if, 同时它也会出现在向下移动的方法中, 停止移动的方法中
此时, 我们应该使用状态模式
当一堆相同情况的if语句出现在两个或多个不同的方法中时, 我们就该考虑用状态(State)去替换它
这里多说一句, 状态模式和策略模式的区别是, 状态模式下用户无法感知和参与对象的状态变化, 而策略模式是可以的
编写状态类
首先, 创建一个基础状态类, BaseState.java:
public abstract class BaseState {
Device device;
protected BaseState(Device device) {
this.device = device;
}
/**
* 心跳链接
*/
public abstract void heartBeat();
}
复制代码
继续创建离线状态, 继承自基础状态, OffLineState.java:
public class OffLineState extends BaseState {
public OffLineState(Device device) {
super(device);
}
@Override
public void heartBeat() {
homing();
}
public void homing() {
try {
device.homing();
device.setState(new InitState(device));
} catch (IOException e) {
device.setState(new OffLineState(device));
}
}
}
复制代码
可以看到, 状态的变化是在内部, 用户无法感知
接下来创建初始化类, InitState.java:
public class InitState extends BaseState {
public InitState(Device device) {
super(device);
}
@Override
public void heartBeat() {
try {
if (device.isMove()) {
return;
}
device.setZeroPosition(device.currentPosition());
device.setState(new OnLineState(device));
} catch (IOException e) {
device.setState(new OffLineState(device));
}
}
}
复制代码
替换方法
接下来, 我们只需要在具体的业务逻辑中, 将代码device.heartBeat()
替换为device.getState().heartBeat()
这里不再赘述, 简单展示下笔者的业务相关代码:
public class Connector {
private static final int INTERVAL = 2000;
@Async
public void connect(Device device) {
try {
while(true) {
device.getState().heartBeat();
Thread.sleep(INTERVAL);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
复制代码
总结
最后总结下状态模式的特点:
- 状态类拥有相同的public方法
- 状态类拥有一个属性指向使用此状态的实体类
- 状态类在内部自动切换状态, 用户无法感知
- 用于替换大块重复出现的if语句
原创文章,作者:睿达君,如若转载,请注明出处:https://zrrd.net.cn/1629.html