一 :任务要求
本次的程序任务和要求如上图所示,需要有4部电梯同时运行,每部电梯都有自己的限制且被同一控制器所控制,希望有图形显示效果,本次的任务我们组已经完成,关于编程的历程与总结现在就一一道来。
二:初步构想阶段
我们先尝试解决最核心的问题,即电梯的调度算法问题,初步构思是这样的,电梯根据当前控制器内所要到的楼层信息判断是向下运行或向上运行,并向上或向下运行至控制器内楼层的最大或最小值,期间出现的所有楼层信息都加入到控制器内,若有比最值更大或更小的信息不予理会,只是加入控制器中,每到一楼层就判断控制器内是否有该楼层,有则在该层停留,并移除控制器内该层信息,无则继续运行,运行至最值处,重新从控制器内找出最值,并判断向上或向下运行,如此循环。当控制器内没有信息后,电梯等待一段时间后会回到初值处。
代码如下:
1 public void down()//定义一个下降函数 便于复用
2 {
3 for(;cout>=con.getmin();cout--)
4 {
5 vie.map.get(new Point(250-50*panmode,500-cout*20)).setBackground(Color.black);
6 if(con.getlist(this.mode).contains(cout))
7 {
8 con.remove(cout);
9 System.out.println("到达"+cout+"层");
10 changepeople();
11 try {
12 Thread.sleep(500);
13 } catch (InterruptedException e) {
14 // TODO Auto-generated catch block
15 e.printStackTrace();
16 }
17 if(cout==con.getmin())
18 break;
19 }
20 if(cout==con.getmin())
21 break;
22 try {
23 Thread.sleep(200);
24 vie.map.get(new Point(250-50*panmode,500-cout*20)).setBackground(Color.white);
25 } catch (InterruptedException e) {
26 // TODO Auto-generated catch block
27 e.printStackTrace();
28 }
29 }
30 }
31 public void run() //电梯运行算法 主要运行函数
32 {
33 while(true)
34 {
35 while(!con.getlist(this.mode).isEmpty())
36 {
37 con.setmami();
38 if(con.getmax()>cout) //和下面的if组成判断电梯是否向上运行 否则向下运行
39 {
40 if(con.getmin()>cout||(con.getmax()-cout)<=(cout-con.getmin()))
41 {
42 for(;cout<=con.getmax();cout++)
43 {
44 vie.map.get(new Point(250-50*panmode,500-cout*20)).setBackground(Color.black);
45 if(con.getlist(this.mode).contains(cout))
46 {
47 con.remove(cout);
48 System.out.println("到达"+cout+"层");
49 changepeople();
50 try {
51 Thread.sleep(500);
52 } catch (InterruptedException e) {
53 // TODO Auto-generated catch block
54 e.printStackTrace();
55 }
56 if(cout==con.getmax())
57 break;
58 }
59 if(cout==con.getmax())
60 break;
61 try {
62 Thread.sleep(200);
63 vie.map.get(new Point(250-50*panmode,500-cout*20)).setBackground(Color.white);
64 } catch (InterruptedException e) {
65 // TODO Auto-generated catch block
66 e.printStackTrace();
67 }
68 }
69 }
70 else
71 down();
72 }
73 else //电梯向下运行的算法
74 down();
75 }
76 try {
77 Thread.sleep(1000);
78 } catch (InterruptedException e) {
79 // TODO Auto-generated catch block
80 e.printStackTrace();}
81 while(con.getlist(this.mode).isEmpty()&&cout!=incout) //无任务回到初始楼层的函数
82 {
83 vie.map.get(new Point(250-50*panmode,500-cout*20)).setBackground(Color.white);
84 if(cout>incout)
85 {
86 cout--;
87 vie.map.get(new Point(250-50*panmode,500-cout*20)).setBackground(Color.black);
88 try {
89 Thread.sleep(200);
90 } catch (InterruptedException e) {
91 // TODO Auto-generated catch block
92 e.printStackTrace();
93 }
94 }
95 if(cout<incout)
96 {
97 cout++;
98 vie.map.get(new Point(250-50*panmode,500-cout*20)).setBackground(Color.black);
99 try {
100 Thread.sleep(200);
101 } catch (InterruptedException e) {
102 // TODO Auto-generated catch block
103 e.printStackTrace();
104 }
105 }
106 }
107 }
108 }
109 }
我这里是从全部完成后的代码上截取出的算法部分,有图形显示的代码和一些实现其他功能的代码,初步构想时只是做出了算法,并在dos模拟。
三:开始构思整个代码结构
代码用java编写,需要一个控制器类型,一个电梯类型,此电梯类型需要能设置多个模式,并且实现多线程运行,最后还要定义一个图形的显示类。这只是初步构思,后面还要加入上人下人判断人数的方法。
各模块的代码如下:
1,主程序模块
1 public class Themin {
2 public static void main(String[] args)
3 {
4 View vie=new View(); //图形界面对象
5 Contro con=new Contro(vie); //控制器对象
6 vie.setcon(con);
7 Elevator ele1=new Elevator(con,vie); //一个电梯对象
8 ele1.setpeople(10); //设置电梯最大载人
9 ele1.setmode(0,0); //设置电梯模式
10 ele1.setinitcout(2); //设置电梯初始楼层
11 Elevator ele2=new Elevator(con,vie);
12 ele2.setpeople(20);
13 ele2.setmode(0,3);
14 ele2.setinitcout(5);
15 Elevator ele3=new Elevator(con,vie);
16 ele3.setpeople(10);
17 ele3.setmode(1,1);
18 ele3.setinitcout(11);
19 Elevator ele4=new Elevator(con,vie);
20 ele4.setpeople(10);
21 ele4.setmode(2,2);
22 ele4.setinitcout(8);
23 (new Thread(ele1)).start(); //电梯运行
24 (new Thread(ele2)).start();
25 (new Thread(ele3)).start();
26 (new Thread(ele4)).start();
27 }
28 }
创建图形对象,创建控制器对象,创建4个各种类型的电梯对象,开始运行。
2,控制模块
1 class Contro//控制模块类
2 {
3 private ArrayList<Integer> arr;//记录需要到达的楼层
4 private Integer max,min;//记录到达楼层的最大值,最小值
5 private ArrayList<Integer> jarr;//设置一个存奇数楼层的表
6 private ArrayList<Integer> darr;//存偶数楼层
7 View vie;
8 Contro(View vie)//构造函数
9 {
10 arr=new ArrayList<Integer>();
11 jarr=new ArrayList<Integer>();
12 darr=new ArrayList<Integer>();
13 max=0;
14 min=0;
15 this.vie=vie;
16 }
17 public void add(Integer i)//添加到达楼层
18 {
19 if(i>=0&&i<=21)
20 {
21 if(!arr.contains(i))
22 {
23 vie.map.get(new Point(300,500-i*20)).setBackground(Color.red);
24 arr.add(i);
25 if(i%2==0)
26 darr.add(i);
27 else
28 jarr.add(i);
29 }
30 }
31 }
32 public void remove(Integer i)//取消一个任务楼层
33 {
34 vie.map.get(new Point(300,500-i*20)).setBackground(Color.white);
35 arr.remove(i);
36 if(i%2==0)
37 darr.remove(i);
38 else
39 jarr.remove(i);
40 }
41 public void setmami()//根据当前信息设置最大值,最小值
42 {
43 min=arr.get(0);
44 max=arr.get(0);
45 for(Integer in:arr)
46 {
47 if(in>max)
48 max=in;
49 if(in<min)
50 min=in;
51 }
52 }
53 public Integer getmin()//得到最小楼层值
54 {
55 return min;
56 }
57 public Integer getmax()//得到最大楼层值
58 {
59 return max;
60 }
61 public ArrayList<Integer> getlist(int mode)//得到存储楼层信息的列表
62 {
63 if(mode==0)
64 return arr;
65 if(mode==1)
66 return jarr;
67 if(mode==2)
68 return darr;
69 else
70 return null;
71 }
72 }
这是控制模块的代码,方法有add()添加一个楼层信息,remove()取消一个楼层信息,getmin(),getmax()获取最小和最大楼层,getlist()获取控制信息的链表,setmami()根据当前信息求最大最小楼层。
3,电梯模块
1 class Elevator implements Runnable//一个电梯的类型,实现多线程
2 {
3 private Integer cout,incout;//记录电梯位置
4 private int peoplecout; //记录电梯内人数
5 private int people; //电梯允许载人最大人数
6 int mode,panmode; //电梯的模式
7 View vie;
8 Contro con;
9 Elevator(Contro con,View vie)//构造函数
10 {
11 this.con=con;
12 this.vie=vie;
13 this.peoplecout=0;//设置每个电梯初始人数为0
14 }
15 public void setmode(int mode,int panmode)//设置电梯的模式 0全 1单 2双
16 {
17 this.mode=mode;
18 this.panmode=panmode;
19 }
20 public void setinitcout(Integer cout)//设置初始楼层
21 {
22 this.incout=cout;
23 this.cout=cout;
24 vie.map.get(new Point(250-panmode*50,500-cout*20)).setBackground(Color.black);
25 vie.map.get(new Point(250-panmode*50,60)).setText(peoplecout+"");
26 }
27 public void setpeople(int i)//设置最大载人的函数
28 {
29 this.people=i;
30 }
31 public void changepeople()//到达某层后人的上下情况设置函数
32 {
33
34 }
35 public void down()//定义一个下降函数 便于复用
36 {
37
38 }
39 }
由于代码有些长,一些方法的内部实现省略了,该电梯类首先要实现Runnable接口实现多线程,使多部电梯可以同时运行,setmode()设置电梯的模式,单楼层,双楼层,或全楼层,setinitcout()设置电梯的初始楼层,setpeople()设置电梯的最大载人数的函数,changepeople()电梯每到一层上下人数记录的函数,run()主运行函数。该类型定义时需要把图形界面对象,控制器对象传进来。
4,图形显示模块
1 class View extends JFrame //此类是电梯的图形显示类
2 {
3 HashMap<Point,JButton> map=new HashMap<Point,JButton>();
4 private JPanel panel;
5 Contro con;
6 JDialog dia;
7 JTextField uptex,downtex;
8 int upcout,downcout;
9 JButton jbu;
10 private JButton contro=new JButton();
11 View()
12 {
13 init();
14 }
15 public void init()//初始化
16 {
17 this.setBounds(250,100,500,550);
18 this.add(setpanel());
19 this.setTitle("键盘0-9对应0-9层f1-f12对应10-21层");
20 this.setdia();
21 this.setResizable(false);
22 myevent();
23 this.setVisible(true);
24 }
25 public void setcon(Contro con)//控制模块传进来
26 {
27 this.con=con;
28 }
29 public void setdia()//设置人数的窗口
30 {
31
32 }
33 public JPanel setpanel()//设置模板
34 {
35
36 }
37 public void getcout()//得到上下人数的函数
38 {
39
40 }
41 private void myevent()//所有监听器
42 {
43
44 }
45 }
上面是该电梯的图形显示类(内部实现已省略),思路很简单,首先类继承JFarme,setpanel()设置模板,setdia()输入上下人数的弹出窗口,getcout()接收上下人数的窗口,myevent()所有的监听器,主要是监听键盘信息,键盘0-9对应电梯0-9层,f1-f12对应电梯10-21层。初步显示效果如下图,还没有添加电梯。最右边是楼层好,最上层是每部电梯的当前人数。
5,显示效果
添加电梯后及运行效果如下,每添加一个楼层信息对应的层数会变红,黑色代表电梯。效果还是很明显的
没添加电梯的显示效果
刚初始化完,没有添加控制信息,黑色代表电梯,最上部有当前人数的值。
添加控制信息后对应楼层变红,电梯会自动运行,可实时键盘添加控制信息。
到达一个任务楼层后会弹出窗口,输入上下车的人数,最上面的计数会变化,超出最大值要重新输入,小于0会直接抛出异常程序终止。
四,遇到问题的解决方法
1,输入上下人数窗口的弹出问题
在现实中,4部电梯的上下人是同时进行的,这可以实现,把记录人数的方法不设置同步就可以了,也就是程序运行时可能最多会弹出4个输入窗口,这虽然符合现实但不利于我们在程序里模拟电梯运行,而且4个窗口同时计数也会极大的增加程序的难度,所以我直接在变化人数的方法里设置了同步,一次只会弹出一个窗口,剩下的电梯人数变化时需要等待正在改变人数的电梯运行完才能变化,也就是说,一次只能一个电梯改变其内的人数,其后的电梯运行到任务楼层后只能停在原地等待,改变完的电梯会继续运动,这虽然和现实不符,但对于一个电梯模拟程序来说更便于使用。
2,键盘监听的问题
电梯楼层是0-21层,键盘所对应数字只有0-9,所以我选择用f1-f12代替10-21层,只需键盘监听到的值减去一个特定的数字就可完成。
五,不足之处
本打算实现实时控制,即实时搜索最大值最小值,实时判断控制信息是否为空,本以为很简单,只需每次添加控制信息时使其有序,这样实时取最前或最后面的值判断最大最小值就可以了,这种电梯我也实现了,在只有一个电梯时会很好的运行,然而在电梯变多后,因为一些并发问题使程序容易出现bug,没法解决故放弃,其间思考可能是移除电梯控制信息和判断电梯控制信息出现并发错误导致,同步代码后依然未解决。
六,总结
通过本次结对编程我学习到了很多,一个人的力量是有限的,尤其是在编程这种高度需要逻辑思维的事情上,多个人一起合作更容易解决程序漏洞,让程序尽可能完美,每个人的认知也是有局限的,多人合作更容易出来各种奇思妙想,让程序功能更加丰富多彩,结对编程也考验着我们的合作能力,这些都让我在这次编程中获得了极大的进步。