1. 程式人生 > >黑馬程式設計師------面試題------交通燈管理系統

黑馬程式設計師------面試題------交通燈管理系統

------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a>、期待與您交流! ----------

一、模擬實現十字路口的交通燈管理系統邏輯

具體需求如下

非同步隨機生成按照各個路線行駛的車輛。
例如:
       由南向而來去往北向的車輛 ---- 直行車輛
       由西向而來去往南向的車輛 ---- 右轉車輛
       由東向而來去往南向的車輛 ---- 左轉車輛
       。。。
訊號燈忽略黃燈,只考慮紅燈和綠燈。
應考慮左轉車輛控制訊號燈,右轉車輛不受訊號燈控制。
具體訊號燈控制邏輯與現實生活中普通交通燈控制邏輯相同,不考慮特殊情況下的控制邏輯。
注:南北向車輛與東西向車輛交替放行,同方向等待車輛應先放行直行車輛而後放行左轉車輛。
每輛車通過路口時間為1秒(提示:可通過執行緒Sleep的方式模擬)。
隨機生成車輛時間間隔以及紅綠燈交換時間間隔自定,可以設定。
不要求實現GUI,只考慮系統邏輯實現,可通過Log方式展現程式執行結果。

二、分析:

Road類表示路線,總共有12條路線,即系統中總共要產生12個Road例項物件。
每條路線上隨機增加新的車輛,增加到一個集合中儲存。
為了統一程式設計模型,可以假設每條路線都有一個紅綠燈對其進行控制。
其中在4個右拐彎一直可以通車,所以燈為常綠。
其他8條線路兩兩成對,可分4組。
所以,程式只需考慮圖中標註了數字號的4條路線的控制燈的切換順序,這4條路線相反方向的路線的控制燈跟隨這4條路線切換,不必額外考慮。
即,路線1行駛完成後路線2行駛,依次路線3、4,然後迴圈 路線1、2、3、4。


Lamp類來表示一個交通燈,每個交通燈都維護一個狀態:亮(綠)或不亮(紅),每個交通燈要有變亮和變黑的方法,並且能返回自己的亮黑狀態。
總共有12條路線,所以,系統中總共要產生12個交通燈。右拐彎的路線本來不受燈的控制,設定這些燈為常亮狀態,即永遠不變黑。
另外8個燈,它們是兩兩成對的,可以歸為4組,
所以,只要從這4組中各取出一個燈,對這4個燈依次輪詢變亮,與這4個燈方向對應的燈則隨之一同變化,
因此Lamp類中要有一個變數來記住自己相反方向的燈,在一個Lamp物件的變亮和變黑方法中,將對應方向的燈也變亮和變黑。每個燈變黑時,都伴隨者下一個燈的變亮,
Lamp類中還用一個變數來記住自己的下一個燈。
無論在程式的什麼地方去獲得某個方向的燈時,每次獲得的都是同一個例項物件,所以Lamp類改用列舉來做顯然具有很大的方便性,永遠都只有代表
12個方向的燈的例項物件。

三、程式碼實現

1)Road類

每個Road物件都有一個name成員變數來代表方向,有一個vehicles成員變數來代表方向上的車輛集合。
在Road物件的構造方法中啟動一個執行緒每隔一個隨機的時間向vehicles集合中增加一輛車(用一個“路線名_id”形式的字串進行表示)。
在Road物件的構造方法中啟動一個定時器,每隔一秒檢查該方向上的燈是否為綠,是則列印車輛集合和將集合中的第一輛車移除掉。

  1. publicclass Road {  
  2.     private List<String> vechicles = new ArrayList<String>();  
  3.     private String name = null;  
  4.     public Road(String name) {  
  5.     this.name = name;  
  6.     // 模擬車輛不斷隨機上路的過程
  7.     ExecutorService pool = Executors.newSingleThreadExecutor();  
  8.     pool.execute(new Runnable() {  
  9.         publicvoid run() {  
  10.         for (int i = 1; i < 1000; i++) {  
  11.             try {  
  12.             Thread.sleep((new Random().nextInt(10) + 1) * 1000);  
  13.             } catch (InterruptedException e) {  
  14.             e.printStackTrace();  
  15.             }  
  16.             vechicles.add(Road.this.name + "_" + i);  
  17.         }  
  18.         }  
  19.     });  
  20.     // 每隔一秒檢查對應的燈是否為綠,是則放行一輛車
  21.     ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  
  22.     timer.scheduleAtFixedRate(new Runnable() {  
  23.         publicvoid run() {  
  24.         if (vechicles.size() > 0) {  
  25.             boolean lighted = Lamp.valueOf(Road.this.name).isLighted();  
  26.             if (lighted) {  
  27.             System.out.println(vechicles.remove(0)  
  28.                 + " is traversing !");  
  29.             }  
  30.         }  
  31.         }  
  32.     }, 11, TimeUnit.SECONDS);  
  33.     }  
  34. }  

2)Lamp類

系統中有12個方向上的燈,在程式的其他地方要根據燈的名稱就可以獲得對應的燈的例項物件,綜合這些因素,將Lamp類用java5中的列舉形式定義更為簡單。
每個Lamp物件中的亮黑狀態用lighted變量表示,選用S2N、S2W、E2W、E2N這四個方向上的Lamp物件依次輪詢變亮,Lamp物件中還要有一個oppositeLampName變數來表示它們相反方向的燈,再用一個nextLampName變數來表示此燈變亮後的下一個變亮的燈。這三個變數用構造方法的形式進行賦值,因為列舉元素必須在定義之後引用,所以無法再構造方法中彼此相互引用,所以,相反方向和下一個方向的燈用字串形式表示。 
增加讓Lamp變亮和變黑的方法:light和blackOut,對於S2N、S2W、E2W、E2N這四個方向上的Lamp物件,這兩個方法內部要讓相反方向的燈隨之變亮和變黑,blackOut方法還要讓下一個燈變亮。
除了S2N、S2W、E2W、E2N這四個方向上的Lamp物件之外,其他方向上的Lamp物件的nextLampName和oppositeLampName屬性設定為null即可,並且S2N、S2W、E2W、E2N這四個方向上的Lamp物件的nextLampName和oppositeLampName屬性必須設定為null,以便防止light和blackOut進入死迴圈。

  1. <span style="font-size:14px">publicenum Lamp {  
  2.     /* 每個列舉元素各表示一個方向的控制燈 */
  3.     S2N("N2S""S2W"false), S2W("N2E""E2W"false), E2W("W2E""E2S"false), E2S(  
  4.         "W2N""S2N"false),  
  5.     /* 下面元素表示與上面的元素的相反方向的燈,它們的“相反方向燈”和“下一個燈”應忽略不計! */
  6.     N2S(nullnullfalse), N2E(nullnullfalse), W2E(nullnullfalse), W2N(  
  7.         nullnullfalse),  
  8.     /* 由南向東和由西向北等右拐彎的燈不受紅綠燈的控制,所以,可以假想它們總是綠燈 */
  9.     S2E(nullnulltrue), E2N(nullnulltrue), N2W(nullnulltrue), W2S(  
  10.         nullnulltrue);  
  11.     private Lamp(String opposite, String next, boolean lighted) {  
  12.     this.opposite = opposite;  
  13.     this.next = next;  
  14.     this.lighted = lighted;  
  15.     }  
  16.     /* 當前燈是否為綠 */
  17.     privateboolean lighted;  
  18.     /* 與當前燈同時為綠的對應方向 */
  19.     private String opposite;  
  20.     /* 當前燈變紅時下一個變綠的燈 */
  21.     private String next;  
  22.     publicboolean isLighted() {  
  23.     return lighted;  
  24.     }  
  25.     /** 
  26.      * 某個燈變綠時,它對應方向的燈也要變綠 
  27.      */
  28.     publicvoid light() {  
  29.     this.lighted = true;  
  30.     if (opposite != null) {  
  31.         Lamp.valueOf(opposite).light();  
  32.     }  
  33.     System.out.println(name() + " lamp is green,下面總共應該有6個方向能看到汽車穿過!");  
  34.     }  
  35.     /** 
  36.      * 某個燈變紅時,對應方向的燈也要變紅,並且下一個方向的燈要變綠 
  37.      *  
  38.      * @return 下一個要變綠的燈 
  39.      */
  40.     public Lamp blackOut() {  
  41.     this.lighted = false;  
  42.     if (opposite != null) {  
  43.         Lamp.valueOf(opposite).blackOut();  
  44.     }  
  45.     Lamp nextLamp = null;  
  46.     if (next != null) {  
  47.         nextLamp = Lamp.valueOf(next);  
  48.         System.out.println("綠燈從" + name() + "-------->切換為" + next);  
  49.         nextLamp.light();  
  50.     }  
  51.     return nextLamp;  
  52.     }  
  53. }</span>  

3)LampController類

整個系統中只能有一套交通燈控制系統,所以,LampController類最好是設計成單例。
LampController構造方法中要設定第一個為綠的燈。
LampController物件的start方法中將當前燈變綠,然後啟動一個定時器,每隔10秒將當前燈變紅和將下一個燈變綠。

  1. <span style="font-size:14px">publicclass LampController {  
  2.     private Lamp currentLamp;  
  3.     public LampController() {  
  4.     // 剛開始讓由南向北的燈變綠;
  5.     currentLamp = Lamp.S2N;  
  6.     currentLamp.light();  
  7.     /* 每隔10秒將當前綠燈變為紅燈,並讓下一個方向的燈變綠 */
  8.     ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  
  9.     timer.scheduleAtFixedRate(new Runnable() {  
  10.         publicvoid run() {  
  11.         currentLamp = currentLamp.blackOut();  
  12.         }  
  13.     }, 1010, TimeUnit.SECONDS);  
  14.     }  
  15. }</span>  

4)MainClass類

用for迴圈創建出代表12條路線的物件。
接著再獲得LampController物件並呼叫其start方法。

  1. publicclass MainClass {  
  2.     /** 
  3.      * @param args 
  4.      */
  5.     publicstaticvoid main(String[] args) {  
  6.     /* 產生12個方向的路線 */
  7.     String[] directions = new String[] { "S2N""S2W""E2W""E2S""N2S",  
  8.         "N2E""W2E""W2N""S2E""E2N""N2W""W2S" };  
  9.     for (int i = <