日常编码中,我们常需要为各种业务进行建模,为工厂中的任务调度建模就很有意思的,它的主要流程是基本是这样:
1.调度员将工件图纸交付给工人,这是任务的下达.
2.工人工作,完成工件,这是任务的进行过程.
3.工件完成后,工人将图纸和工件返还给调度员,或者到了确定的时间后由调度员去取.这是任务的完成.
4.重复上述三个步骤.
在这个流程中,还存在一些特征:
1.工人可以有多项任务,但他在一个时间只能做一个活,具体做那个由任务的优先级确定.
2.任务完成后要让调度员知道,现实中是工人来找调度员或者调度员找工人来实现的.一般来说调度员找工人的情况居多.
从上述情况分析,我们需要任务,工人,调度员三个类来完成建模,另外为了方便任务的存储和管理,还需要一个任务串类来辅助.
首先看任务类,除了Id,name这样的常规属性外,它应该具有下面的成员:
1.完成所需要的总工时数.
2.已经完成的工时数,它和总工时数的比值就是完成比例.
3.优先级.
4.任务接受者,也就是工人.
5.任务发布者,也就是调度员.
它还应该具有一个重要函数,这个函数应该是定时被执行的,执行时先增加已经完成的工时数,然后看是否完成,是则把自己从任务接受者的待完成任务链表中删除,再添加到任务发布者的已完成任务链表中去.
具体代码如下:
package com.sitinspring.taskmanagement.domain;
import com.sitinspring.taskmanagement.util.IdUtil;
public class Task implements Comparable {
private String id;
private String name;
// 完成需消耗的工时数
private int manHour;
// 已经完成的工时数
private int completed;
// 优先级
private int priority;
// 接受任务者
private Worker worker;
// 发布任务者
private Attemper attemper;
public Task(String name, int manHour) {
this(name, manHour, 0);
}
public Task(String name, int manHour, int priority) {
id = IdUtil.generateId();
this.name = name;
this.manHour = manHour;
this.priority = priority;
this.completed = 0;
}
// 任务是否完成
public boolean isCompleted() {
return completed >= manHour;
}
// 添加完成度
public void addCompleted(int n) {
completed += n;
if (isCompleted()) {
completed = manHour;
if (worker != null) {
// 完成后让工人把自己从任务列表中删除
worker.removeTask(this);
}
if (attemper != null) {
// 完成后把任务添加到调度员(任务发送者)的完成任务链表
attemper.addCompletedTask(this);
}
}
}
public int compareTo(Object obj) {
Task another = (Task) obj;
return (another.priority) - this.priority;
}
public String toString() {
return "任务名:" + name + " 工人名:" + worker.getName() + " 完成度:" + completed
* 100 / manHour + "%";
}
public int getCompleted() {
return completed;
}
public void setCompleted(int completed) {
this.completed = completed;
}
public int getManHour() {
return manHour;
}
public void setManHour(int manHour) {
this.manHour = manHour;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public Worker getWorker() {
return worker;
}
public void setWorker(Worker worker) {
this.worker = worker;
}
public Attemper getAttemper() {
return attemper;
}
public void setAttemper(Attemper attemper) {
this.attemper = attemper;
}
}
其次再来看任务串类,它用于管理多个任务,自然它必定具有一个链表成员,类中大部分函数都是围绕这个成员设计的,另外考虑到工人需要取得最优先的任务,链表需要按任务的优先级排序,然后做一个函数用于取得最开头的任务即优先级最高的任务.isCompleted函数用于判断所有任务是否完成.
代码如下:
package com.sitinspring.taskmanagement.domain;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class TaskBunch{
// 任务链表
private List<Task> tasks;
public TaskBunch(){
tasks=new LinkedList<Task>();
}
// 取得最优先任务
public Task getTopTask(){
return tasks.get(0);
}
// 取得任务个数
public int getSize(){
return tasks.size();
}
// 判断是否完成
public boolean isCompleted(){
for(Task task:tasks){
if(task.isCompleted()==false){
return false;
}
}
return true;
}
// 添加任务
public void addTask(Task task){
tasks.add(task);
Collections.sort(tasks);
}
// 删除任务
public void removeTask(Task task){
tasks.remove(task);
}
}
接下来是工人类,它有一个任务串成员用于存储待完成任务,由于它需要定时执行任务,因此需要实现Runnable接口,在run函数中处理任务,另外再做一个doWork()让线程工作起来.工作时首先取得待完成任务链表中的优先级最高的任务,执行任务中的addCompleted方法,如果待完成任务一直没完的话就不断的执行,直到所有任务完成为止.至于任务完成后的从自己的待完成任务链表中删除及添加到调度员的已完成任务链表中的工作由任务自己完成,工人无需管理,具体请看Task类的addCompleted方法.
run函数中,sleep的1000毫秒当一个小时看,这里工人基本是当24小时的班,即机器不闲着人三班倒,如果是日常的八小时任务则可以先取一下当前时间是否在工作时间内,是则继续干,如果不是应该加入继续休眠sleep的代码.
工人类代码如下:
package com.sitinspring.taskmanagement.domain;
import com.sitinspring.taskmanagement.util.IdUtil;
public class Worker implements Runnable{
private String id;
private String name;
// 任务列表
private TaskBunch taskBunch;
// 工作速度
private int speed;
public Worker(String name,int speed){
id=IdUtil.generateId();
this.name=name;
this.speed=speed;
taskBunch=new TaskBunch();
}
// 添加任务
public void addTask(Task task){
task.setWorker(this);
taskBunch.addTask(task);
}
// 删除任务
public void removeTask(Task task){
taskBunch.removeTask(task);
}
// 开始干活
public void doWork(){
Thread thread=new Thread(this);
thread.start();
}
// 真正干活
public void run(){
while(!taskBunch.isCompleted()){
try{
Thread.sleep(1000);
Task task=taskBunch.getTopTask();
task.addCompleted(speed);
System.out.println("正在处理的任务"+task+" 还需处理"+taskBunch.getSize()+"个.");
}
catch(Exception ex){
ex.printStackTrace();
}
}
System.out.println("工人"+name+"的全部任务处理完毕!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
}
最后是调度员类,它的主要任务是生成任务以及管理已经完成的任务,代码比较简单:
package com.sitinspring.taskmanagement.domain;
import com.sitinspring.taskmanagement.util.IdUtil;
public class Attemper{
private String id;
private String name;
private TaskBunch completedTasks;
public Attemper(String name){
id=IdUtil.generateId();
this.name=name;
completedTasks=new TaskBunch();
}
public Task generateTask(String name,int manHour,int priority){
Task task=new Task(name,manHour,priority);
task.setAttemper(this);
return task;
}
public void addCompletedTask(Task task){
completedTasks.addTask(task);
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
具体示例执行过程如下:
Attemper Attemper=new Attemper("调度员");
Worker commonWorker=new Worker("普通工人一",2);
commonWorker.addTask(Attemper.generateTask("任务1",8,1));
commonWorker.addTask(Attemper.generateTask("任务2",9,2));
commonWorker.addTask(Attemper.generateTask("任务3",20,3));
commonWorker.doWork();
Worker skilledWorker=new Worker("熟练工人二",3);
skilledWorker.addTask(Attemper.generateTask("任务4",5,2));
skilledWorker.addTask(Attemper.generateTask("任务5",30,2));
skilledWorker.addTask(Attemper.generateTask("任务6",16,3));
skilledWorker.doWork();
Worker oldSkilledWorker=new Worker("老熟练工人三",5);
oldSkilledWorker.addTask(Attemper.generateTask("任务7",15,2));
oldSkilledWorker.addTask(Attemper.generateTask("任务8",13,2));
oldSkilledWorker.addTask(Attemper.generateTask("任务9",7,3));
oldSkilledWorker.doWork();
执行输出如下:
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:10% 还需处理3个.
正在处理的任务任务名:任务6 工人名:熟练工人二 完成度:18% 还需处理3个.
正在处理的任务任务名:任务9 工人名:老熟练工人三 完成度:71% 还需处理3个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:20% 还需处理3个.
正在处理的任务任务名:任务6 工人名:熟练工人二 完成度:37% 还需处理3个.
正在处理的任务任务名:任务9 工人名:老熟练工人三 完成度:100% 还需处理2个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:30% 还需处理3个.
正在处理的任务任务名:任务6 工人名:熟练工人二 完成度:56% 还需处理3个.
正在处理的任务任务名:任务7 工人名:老熟练工人三 完成度:33% 还需处理2个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:40% 还需处理3个.
正在处理的任务任务名:任务6 工人名:熟练工人二 完成度:75% 还需处理3个.
正在处理的任务任务名:任务7 工人名:老熟练工人三 完成度:66% 还需处理2个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:50% 还需处理3个.
正在处理的任务任务名:任务6 工人名:熟练工人二 完成度:93% 还需处理3个.
正在处理的任务任务名:任务7 工人名:老熟练工人三 完成度:100% 还需处理1个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:60% 还需处理3个.
正在处理的任务任务名:任务6 工人名:熟练工人二 完成度:100% 还需处理2个.
正在处理的任务任务名:任务8 工人名:老熟练工人三 完成度:38% 还需处理1个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:70% 还需处理3个.
正在处理的任务任务名:任务4 工人名:熟练工人二 完成度:60% 还需处理2个.
正在处理的任务任务名:任务8 工人名:老熟练工人三 完成度:76% 还需处理1个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:80% 还需处理3个.
正在处理的任务任务名:任务4 工人名:熟练工人二 完成度:100% 还需处理1个.
正在处理的任务任务名:任务8 工人名:老熟练工人三 完成度:100% 还需处理0个.
工人老熟练工人三的全部任务处理完毕!
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:90% 还需处理3个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:10% 还需处理1个.
正在处理的任务任务名:任务3 工人名:普通工人一 完成度:100% 还需处理2个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:20% 还需处理1个.
正在处理的任务任务名:任务2 工人名:普通工人一 完成度:22% 还需处理2个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:30% 还需处理1个.
正在处理的任务任务名:任务2 工人名:普通工人一 完成度:44% 还需处理2个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:40% 还需处理1个.
正在处理的任务任务名:任务2 工人名:普通工人一 完成度:66% 还需处理2个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:50% 还需处理1个.
正在处理的任务任务名:任务2 工人名:普通工人一 完成度:88% 还需处理2个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:60% 还需处理1个.
正在处理的任务任务名:任务2 工人名:普通工人一 完成度:100% 还需处理1个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:70% 还需处理1个.
正在处理的任务任务名:任务1 工人名:普通工人一 完成度:25% 还需处理1个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:80% 还需处理1个.
正在处理的任务任务名:任务1 工人名:普通工人一 完成度:50% 还需处理1个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:90% 还需处理1个.
正在处理的任务任务名:任务1 工人名:普通工人一 完成度:75% 还需处理1个.
正在处理的任务任务名:任务5 工人名:熟练工人二 完成度:100% 还需处理0个.
工人熟练工人二的全部任务处理完毕!
正在处理的任务任务名:任务1 工人名:普通工人一 完成度:100% 还需处理0个.
工人普通工人一的全部任务处理完毕!
代码下载:
http://www.blogjava.net/Files/sitinspring/TaskManagement20071005131809.rar
以上.