如何实现车库门控制器以跟踪其上次运动方向?
解决Killer Garage Door中暂停恢复原方向的状态模式实现思路
我之前在做类似的状态模式实践时也踩过方向跟踪的坑,结合你的需求,给你几个具体的落地思路和代码示例,应该能解决你JUnit测试失败的问题:
1. 先在上下文类中维护核心状态变量
首先在你的GarageDoor(上下文类)里添加两个关键变量:一个枚举类型记录运动方向,一个字段跟踪上次的运动方向,同时还要记录门的当前位置(因为暂停后需要从当前位置继续运动):
// 定义方向枚举 public enum DoorDirection { UP, DOWN, STOPPED } public class GarageDoor { private DoorState currentState; private DoorDirection lastDirection; private int currentPosition; // 0=完全关闭,100=完全打开 public GarageDoor() { // 初始状态:关闭,方向停止,位置0 currentState = new ClosedState(); lastDirection = DoorDirection.STOPPED; currentPosition = 0; } // 提供状态和方向的访问/修改方法 public void setState(DoorState newState) { this.currentState = newState; } public void setLastDirection(DoorDirection direction) { this.lastDirection = direction; } public DoorDirection getLastDirection() { return lastDirection; } public void updatePosition(int delta) { currentPosition = Math.max(0, Math.min(100, currentPosition + delta)); // 到达边界时自动切换状态(比如到100时切换到OpenState) if (currentPosition == 100) { setState(new OpenState()); setLastDirection(DoorDirection.STOPPED); } else if (currentPosition == 0) { setState(new ClosedState()); setLastDirection(DoorDirection.STOPPED); } } // 外部触发的按钮和障碍物检测方法 public void pressButton() { currentState.pressButton(this); } public void detectObstacle() { currentState.detectObstacle(this); } }
2. 在各状态类中处理方向更新与恢复逻辑
状态模式的核心是每个状态类只负责自己的行为,我们需要在状态切换时同步更新lastDirection,重点处理暂停状态的恢复逻辑:
示例1:关闭状态(ClosedState)
public class ClosedState implements DoorState { @Override public void pressButton(GarageDoor door) { door.setState(new OpeningState()); door.setLastDirection(DoorDirection.UP); // 启动开门计时逻辑(比如每秒调用updatePosition(20),5秒到100) } @Override public void detectObstacle(GarageDoor door) { // 关闭状态下遇障碍物无需处理 } }
示例2:开门状态(OpeningState)
public class OpeningState implements DoorState { @Override public void pressButton(GarageDoor door) { // 运动中按按钮→切换到暂停状态,保留上次方向UP door.setState(new PausedState()); } @Override public void detectObstacle(GarageDoor door) { // 遇障碍物立即反转方向→切换到关门状态,更新方向为DOWN door.setState(new ClosingState()); door.setLastDirection(DoorDirection.DOWN); } }
关键:暂停状态(PausedState)的恢复逻辑
这是解决你问题的核心,按下按钮时根据lastDirection回到对应的运动状态:
public class PausedState implements DoorState { @Override public void pressButton(GarageDoor door) { DoorDirection lastDir = door.getLastDirection(); if (lastDir == DoorDirection.UP) { door.setState(new OpeningState()); // 恢复开门计时,从当前位置继续 } else if (lastDir == DoorDirection.DOWN) { door.setState(new ClosingState()); // 恢复关门计时,从当前位置继续 } // 初始停止状态下按按钮的情况,可根据需求补充 } @Override public void detectObstacle(GarageDoor door) { // 暂停时遇障碍物,可直接反转方向(比如从暂停的关门状态转为开门) door.setLastDirection(door.getLastDirection() == DoorDirection.UP ? DoorDirection.DOWN : DoorDirection.UP); pressButton(door); // 触发恢复逻辑,直接按新方向运动 } }
3. 修复JUnit测试的方向问题
那些标记→的测试用例,本质是暂停恢复时方向判断错误。现在通过lastDirection的跟踪,PausedState能精准回到之前的运动方向:
- 比如测试用例:
开门中→按按钮暂停→再按按钮,现在会继续开门而不是关门 - 遇障碍物的测试:
关门中→检测到障碍物→反转开门,方向会正确更新为UP
内容的提问来源于stack exchange,提问作者Yone




