一 :任務要求
本次的程序任務和要求如上圖所示,需要有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,沒法解決故放棄,其間思考可能是移除電梯控制信息和判斷電梯控制信息出現並發錯誤導致,同步代碼后依然未解決。
六,總結
通過本次結對編程我學習到了很多,一個人的力量是有限的,尤其是在編程這種高度需要邏輯思維的事情上,多個人一起合作更容易解決程序漏洞,讓程序盡可能完美,每個人的認知也是有局限的,多人合作更容易出來各種奇思妙想,讓程序功能更加豐富多彩,結對編程也考驗着我們的合作能力,這些都讓我在這次編程中獲得了極大的進步。