上一篇设计模式——命令模式实战之WCS概要设计(三)基于WCS的逻辑进行了简单抽象,并基于命令模式进行了概要设计。接下来,基于实际仓内情况,进行比较详细的设计。
基础信息
从上图仓库内的情况很复杂,在进行概要设计的时候,需要进行高度的抽象,在详细设计的时候,需要对很多细节进行明确的设计和实现。
这里只基于仓库中的两种设备进行抽象,对场景进行一定的抽象。具体场景如下:
- 五条巷道,一条巷道里面有一台堆垛机(Stacker)
- 每条巷道口有接驳口,要放入当前巷道的货物由输送线(ConveyorLine)送至接驳口
这里涉及到两种设备Stacker
和ConveyorLine
,两种设备的关系是任务执行过程中的两个阶段。文章重点对Stacker
进行设计。
Stacker 控制详细设计
更直观的看一下堆垛机。
图中就是堆垛机,底部是在轨道上的,带有可上下移动并且可以内外伸缩的叉子。
功能点
- 堆垛机的健康状态监控
监控堆垛机的健康状态,确保堆垛机一直在线,对上游的分货位进行通知等逻辑 - 堆垛机的工作线程的健康状态
堆垛机获取到执行命令以后,会有一个执行命令的执行中的一个时间段,需要对工作线程保持监控,如果线程发生异常,需要即时重建工作线程,保证流水线的正常运转。 - 即时获取命令去执行
工作线程要及时获取,待执行的任务或命令,去执行。保证任务被读取到以后,可以准确及时执行。 - 即时反馈命令执行结果
堆垛机执行完以后,需要及时的反馈执行结果,给上游业务逻辑,更新进数据库;以便后续对异常任务人工修复。
分析上述功能点以后,第一思路产生的是实现所有功能,需要多线程、定时任务、阻塞队列、锁 等Java技术实现。
基于队列模型实现
代码流程 如图:
从流程中可以看到核心控制命令顺序和并发性是通过阻塞队列完成的。阻塞队列可以实现任务的有序性和工作线程的阻塞监听。
接下来详细介绍关键类的实现:
堆垛机的实例
// 存放堆垛机实例,
private Map<String/*stacker id*/, Stacker> stackerMap=new HashMap<>();
使用map保存堆垛机的实例,key为堆垛机的id,值为堆垛机实例。
任务队列的声明
// 任务队列
private Map<String/*stacker id*/, LinkedBlockingQueue<StackerTask>> taskQueueMap =new HashMap<>();
使用map声明任务队列,key为堆垛机的id,值为此堆垛机的任务队列,这里使用阻塞队列,工作线程可以利用阻塞队列的阻塞等待特性,实现监听。
堆垛机工作线程监听阻塞队列的核心实现如下 :
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
LinkedBlockingQueue<StackerTask> q = taskQueueMap.get(stacker.getId());
// 阻塞等待任务
while (q.peek() != null) {
StackerTask task = q.poll();
// 执行任务
stacker.action(task, taskCallbackMap.get(task.getTaskId()));
}
}
}, "stacker-"+stacker.getId());
堆垛机的监控实现
if(healthCheckLock