酒店点餐系统开发详解(五)
——任务分配设计
本系统从公平的角度,采取“先来先服务”原则为厨师分配做菜任务,但是顾客在点菜时可能出现指定了某个厨师做某道菜的情况,所以本系统针对未指定厨师的情况设计了一个非指定队列用于保存未指定做菜厨师的任务信息,同时为每个厨师添加了一个指定队列用于存放指定其要做的任务信息。为了更好的分配任务,本系统将厨师分为三种状态:全空闲、半空闲、忙。全空闲,指没有正在做的任务,其指定队列也为空;半空闲,指没有正在进行的任务,但是其指定队列不为空;忙,指有正在进行的任务。
任务分配分两种情况,一是自动分配任务,二是非自动分配任务。自动分配,指每当有做菜任务到达时,先由系统根据现有厨师的状态分配任务,并在终端显示任务分配情况;非自动分配,指厨师在完成某菜品后,在终端输入其厨师编号后显示其下一任务信息。自动分配任务是为了避免在所有厨师都处于全空闲而有新任务到达时,厨师不能知道有任务到达的情况。
自动分配任务流程图:
读取任务模块流程图:
非自动任务分配流程图:
任务分配的具体操作封装在类CTaskManager中,以下为其具体实现:
1、TaskManager.h:
#define CS_BUSY 1 /*忙*/
#define CS_FREE 2 /*全空闲*/
#define CS_HALFFREE 3 /*半空闲*/
//任务结构体
struct TASK{
int deskid;
char dishtime[DISHED_TIME_LEN];
char dishid[DISH_ID_LEN];
char cookid[COOK_ID_LEN];
struct TASK *next;
};
//任务队列
struct TaskQueue{
struct TASK *first;
struct TASK *last;
};
//厨师结构体
struct COOK{
char cookid[COOK_ID_LEN];
int state;
struct TASK *doing; //正在做的任务
struct TaskQueue *assign; //指定的任务队列
};
//厨师队列
struct CookQueue{
int len;
struct COOK *cooks;
};
class CTaskManager
{
private:
int GetFirstHalfFree(int start);
int GetFirstFree(int start);
int FindCook(char *cookid);
struct TASK * CreateTask(int deskid,char *dishtime,char *dishid,char *cookid);
struct TASK * GetHeaderTask(struct TaskQueue *queue);
void ReadAddTask(int deskid,char *dishtime);
void AddToAssign(char *cookid,struct TASK *task);
void AddToNoAssign(struct TaskQueue *temp);
BOOL IsEmptyQueue(struct TaskQueue *queue);
void InitCook(struct COOK *cook,char *cookid);
void AddTaskToQueue(struct TaskQueue *queue, struct TaskQueue *temp);
void AddTaskToQueue(struct TaskQueue *queue,struct TASK *task);
struct TaskQueue *m_noAssign; //未指定队列
struct CookQueue *m_cq;
public:
void AssignTaskToCook(char *cookid);
void AutoAssignTask(int deskid,char *dishtime);
void CreateCookQueue();
CTaskManager();
virtual ~CTaskManager();
};
2、TaskManager.cpp:
#include "stdafx.h"
#include "CookTerminal.h"
#include "CookTerminalDlg.h"
#include "TaskManager.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
extern CCookTerminalApp theApp;
CTaskManager::CTaskManager()
{
m_noAssign = new struct TaskQueue;
m_cq = new struct CookQueue;
m_noAssign->first = m_noAssign->last = NULL;
m_cq->len = 0;
m_cq->cooks = NULL;
}
CTaskManager::~CTaskManager()
{
if(m_noAssign != NULL)
delete m_noAssign;
if(m_cq->cooks != NULL){
for(int i = 0; i < m_cq->len; i++){
if(m_cq->cooks[i].assign != NULL)
delete m_cq->cooks[i].assign;
}
delete[] m_cq->cooks;
}
if(m_cq != NULL)
delete m_cq;
}
//创建厨师队列,并填充结构
void CTaskManager::CreateCookQueue()
{
CString selected;
int len;
//得到实际在岗厨师数
selected.Format("SELECT COUNT(*) as len FROM CookTable WHERE duty=1");
if(theApp.m_DbOp.OpenRecordset(selected) == FALSE)
return;
len = atoi(theApp.m_DbOp.GetAttrValues("len"));
if(len <= 0)
return;
//得到在岗厨师记录集
selected.Format("SELECT cookid FROM CookTable WHERE duty=1");
theApp.m_DbOp.OpenRecordset(selected);
theApp.m_DbOp.MoveFirst();
char cookid[COOK_ID_LEN];
int i = 0;
m_cq->cooks = new COOK[len];
m_cq->len = len;
do{
memset(cookid,0,COOK_ID_LEN);
strncpy(cookid,theApp.m_DbOp.GetAttrValues("cookid"),COOK_ID_LEN);
InitCook(&m_cq->cooks[i++],cookid);
}while(theApp.m_DbOp.MoveNext());
}
//将临时队列添加到非指定队列中
void CTaskManager::AddToNoAssign(struct TaskQueue *temp)
{
if (temp == NULL) return;
AddTaskToQueue(m_noAssign,temp);
}
//添加新任务到某厨师的指定队列中
void CTaskManager::AddToAssign(char *cookid, struct TASK *task)
{
if(task == NULL) return;
int at = FindCook(cookid);
if(at == -1) return;
if(m_cq->cooks[at].state != CS_BUSY)
m_cq->cooks[at].state = CS_HALFFREE;
AddTaskToQueue(m_cq->cooks[at].assign,task);
}
//读取并添加任务,按情况添加到指定或非指定队列
void CTaskManager::ReadAddTask(int deskid, char *dishtime)
{
CString selected;
selected.Format("SELECT dishid,cookid FROM DishedTable WHERE dishedtime='%s' AND deskid=%d",dishtime,deskid);
if(theApp.m_DbOp.OpenRecordset(selected) == FALSE)
return;
if(theApp.m_DbOp.MoveFirst() == FALSE)
return;
struct TaskQueue *temp = new struct TaskQueue;
struct TASK *task = NULL;
char dishid[DISH_ID_LEN],cookid[COOK_ID_LEN];
if(temp == NULL)
return;
temp->first = temp->last = NULL;
do{
memset(dishid,0,DISH_ID_LEN);
memset(cookid,0,COOK_ID_LEN);
strncpy(dishid,theApp.m_DbOp.GetAttrValues("dishid"),DISH_ID_LEN);
strncpy(cookid,theApp.m_DbOp.GetAttrValues("cookid"),COOK_ID_LEN);
task = CreateTask(deskid,dishtime,dishid,cookid);
if(strncmp(task->cookid,"NONE",4) == 0){ //添加到临时队列
if(IsEmptyQueue(temp)) //第一个任务
temp->first = temp->last = task;
else { //添加到队列尾
temp->last->next = task;
temp->last = task;
}
}
else
AddToAssign(cookid,task); //添加到指定队列
}while(theApp.m_DbOp.MoveNext());
AddToNoAssign(temp); //添加到非指定队列
delete temp;
}
//从队列首部取出任务
struct TASK * CTaskManager::GetHeaderTask(struct TaskQueue *queue)
{
struct TASK *task = NULL;
task = queue->first;
queue->first = task->next;
if(IsEmptyQueue(queue))
queue->last = NULL;
return task;
}
//创建并返回一个任务
struct TASK * CTaskManager::CreateTask(int deskid, char *dishtime, char *dishid, char *cookid)
{
struct TASK *task = NULL;
task = new struct TASK;
memset((char*)task,0,sizeof(struct TASK));
if(task != NULL){
task->deskid = deskid;
strncpy(task->dishtime,dishtime,DISHED_TIME_LEN);
strncpy(task->dishid,dishid,DISH_ID_LEN);
strncpy(task->cookid,cookid,COOK_ID_LEN);
task->next = NULL;
}
return task;
}
//找到厨师号为cookid的厨师所在位置,若未找到则返回-1
int CTaskManager::FindCook(char *cookid)
{
int start = 0;
int end = m_cq->len - 1;
int mid,at = -1;
while(start <= end){
mid = (start + end)/2;
if(strncmp(m_cq->cooks[mid].cookid,cookid,COOK_ID_LEN - 1) > 0)
end = mid - 1;
else if(strncmp(m_cq->cooks[mid].cookid,cookid,COOK_ID_LEN - 1) < 0)
start = mid + 1;
else {
at = mid;
break;
}
}
return at;
}
//添加单任务到队列
void CTaskManager::AddTaskToQueue(struct TaskQueue *queue, struct TASK *task)
{
struct TASK *prev,*next;
if(IsEmptyQueue(queue)){
queue->first = queue->last = task;
}
else{
prev = next = queue->first;
while(next != NULL && strncmp(next->dishtime,task->dishtime,DISHED_TIME_LEN - 1) <= 0){
prev = next;
next = prev->next;
}
if(next == NULL){ //追加到尾部
prev->next = task;
queue->last = task;
}
else if(prev == next){ //放到第一个前
queue->first = task;
task->next = next;
}
else { //放到中间位置
prev->next = task;
task->next = next;
}
}
}
//添加多任务到队列
void CTaskManager::AddTaskToQueue(struct TaskQueue *queue, struct TaskQueue *temp)
{
struct TASK *prev,*next;
if(IsEmptyQueue(queue)){
queue->first = temp->first;
queue->last = temp->last;
}
else{
prev = next = queue->first;
while(next != NULL && strncmp(next->dishtime,temp->first->dishtime,DISHED_TIME_LEN - 1) <= 0){
prev = next;
next = prev->next;
}
if(next == NULL){ //追加到尾部
prev->next = temp->first;
queue->last = temp->last;
}
else if(prev == next){ //放到第一个前
queue->first = temp->first;
temp->last->next = next;
}
else { //放到中间位置
prev->next = temp->first;
temp->last->next = next;
}
}
}
//找到第一个 全空闲 的厨师,若无则返回-1
int CTaskManager::GetFirstFree(int start)
{
int at = -1;
if(start < 0)
return at;
while(start <= (m_cq->len - 1)){
if(m_cq->cooks[start].state == CS_FREE){
at = start;
break;
}
start++;
}
return at;
}
//找到第一个 半空闲 的厨师,若无则返回-1
int CTaskManager::GetFirstHalfFree(int start)
{
int at = -1;
if(start < 0)
return at;
while(start <= (m_cq->len - 1)){
if(m_cq->cooks[start].state == CS_HALFFREE){
at = start;
break;
}
start++;
}
return at;
}
//初始化厨师结构体
void CTaskManager::InitCook(struct COOK *cook, char *cookid)
{
strncpy(cook->cookid,cookid,COOK_ID_LEN);
cook->state = CS_FREE;
cook->doing = NULL;
cook->assign = new struct TaskQueue;
cook->assign->first = cook->assign->last = NULL;
}
//判断任务队列是否为空
BOOL CTaskManager::IsEmptyQueue(struct TaskQueue *queue)
{
if(queue->first == NULL)
return TRUE;
else
return FALSE;
}
//自动分配任务
void CTaskManager::AutoAssignTask(int deskid, char *dishtime)
{
int at = 0;
CCookTerminalDlg *m_Parent = (CCookTerminalDlg*)AfxGetMainWnd();
if(m_Parent == NULL){
AfxMessageBox(_T("系统出错!"));
return;
}
ReadAddTask(deskid,dishtime); //读取并添加任务
while(!IsEmptyQueue(m_noAssign)){ //如果非指定队列不为空,则继续寻找
at = GetFirstFree(at); //找到 全空闲 的厨师
if(at == -1) //如果没找到则结束
break;
//为该厨师分配 非指定队列的首任务
m_cq->cooks[at].doing = GetHeaderTask(m_noAssign);
m_cq->cooks[at].state = CS_BUSY;
strncpy(m_cq->cooks[at].doing->cookid,m_cq->cooks[at].cookid,COOK_ID_LEN);
//显示自动任务分配情况
m_Parent->ShowAutoTaskAssign(m_cq->cooks[at]);
}
at = 0;
struct TaskQueue *queue = NULL;
while((at = GetFirstHalfFree(at)) != -1){ //如果 半空闲 的厨师存在,则继续分配任务
queue = m_cq->cooks[at].assign; //取指定队列
if(!IsEmptyQueue(m_noAssign)){ //如果 非指定队列不为空,按先来先服务原则分配任务
if(strncmp(m_noAssign->first->dishtime,queue->first->dishtime,DISHED_TIME_LEN - 1) < 0){
//非指定队列首任务优先,开始非指定队列首任务
m_cq->cooks[at].doing = GetHeaderTask(m_noAssign);
}
else //否则取指定队列首任务
m_cq->cooks[at].doing = GetHeaderTask(queue);
}
else //如果非指定队列为空,则直接开始指定队列首任务
m_cq->cooks[at].doing = GetHeaderTask(queue);
m_cq->cooks[at].state = CS_BUSY;
strncpy(m_cq->cooks[at].doing->cookid,m_cq->cooks[at].cookid,COOK_ID_LEN);
//显示自动任务分配情况
m_Parent->ShowAutoTaskAssign(m_cq->cooks[at]);
}
}
//为厨师分配任务
void CTaskManager::AssignTaskToCook(char *cookid)
{
int at;
struct TaskQueue *queue = NULL;
CCookTerminalDlg *m_Parent = (CCookTerminalDlg*)AfxGetMainWnd();
if(m_Parent == NULL){
AfxMessageBox(_T("系统出错!"));
return;
}
at = FindCook(cookid);
if(at == -1){
AfxMessageBox(_T("在岗厨师中不存在该编号的厨师!"),MB_OK);
return;
}
if(m_cq->cooks[at].doing != NULL){
//显示菜品完成,注意处理完后将空间释放
m_Parent->TaskFinish(m_cq->cooks[at].doing);
m_cq->cooks[at].doing = NULL;
if(IsEmptyQueue(m_cq->cooks[at].assign)) //如果指定队列为空,则置其状态为 空闲,否则为 半空闲
m_cq->cooks[at].state = CS_FREE;
else
m_cq->cooks[at].state = CS_HALFFREE;
}
if(m_cq->cooks[at].state == CS_FREE){ //若该厨师 全空闲,则分配非指定队列的任务
if(!IsEmptyQueue(m_noAssign)){ //非指定不为空,则分配首任务给该厨师
m_cq->cooks[at].doing = GetHeaderTask(m_noAssign);
m_cq->cooks[at].state = CS_BUSY;
}
}
else { //若厨师为 半空闲,则按先来先服务原则分配任务
queue = m_cq->cooks[at].assign;
if(!IsEmptyQueue(m_noAssign)){
//非指定队列不为空且优先于指定队列首任务
if(strncmp(m_noAssign->first->dishtime,queue->first->dishtime,DISHED_TIME_LEN - 1) < 0)
m_cq->cooks[at].doing = GetHeaderTask(m_noAssign);
else
m_cq->cooks[at].doing = GetHeaderTask(queue);
}
else //非指定队列为空,直接分配指定队列首任务
m_cq->cooks[at].doing = GetHeaderTask(queue);
m_cq->cooks[at].state = CS_BUSY;
}
if(m_cq->cooks[at].state == CS_BUSY){
strncpy(m_cq->cooks[at].doing->cookid,m_cq->cooks[at].cookid,COOK_ID_LEN);
//显示手动任务分配情况
m_Parent->ShowTaskAssign(m_cq->cooks[at]);
}
else
m_Parent->ShowNoTask(); //提示没有任务
}
源代码下载地址:http://download.youkuaiyun.com/source/2406335 标题有误,请见谅...