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

黑馬程式設計師_面試題1(交通燈管理系統)

一.專案需求:

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

      非同步隨機生成按照各個路線行駛的車輛。

      例如:

      由南向而來去往北向的車輛 ---- 直行車輛

      由西向而來去往南向的車輛 ---- 右轉車輛

      由東向而來去往南向的車輛 ---- 左轉車輛

      。。。

     訊號燈忽略黃燈,只考慮紅燈和綠燈。

     應考慮左轉車輛控制訊號燈,右轉車輛不受訊號燈控制。

     具體訊號燈控制邏輯與現實生活中普通交通燈控制邏輯相同,不考慮特殊情況下的控制邏輯。

     注:南北向車輛與東西向車輛交替放行,同方向等待車輛應先放行直行車輛而後放行左轉車輛。

     每輛車通過路口時間為1秒(提示:可通過執行緒Sleep的方式模擬)。

     隨機生成車輛時間間隔以及紅綠燈交換時間間隔自定,可以設定。



二.開發前分析:

  1. 一個方向到其他方向有3條線路,4個方向共12條線路,為了統一程式設計模型,

     可以假設每條路都有一個紅綠燈對其進行控制, 右轉向的4個路口的控制燈可以假設為常亮綠燈狀態。

  2.為了思路清晰,先思考一個方向的路線問題。

  3.初步設想所擁有的物件:紅綠燈,紅綠燈的控制系統,(汽車),路線。

  4.汽車要看所線上路上的紅綠燈,並且判斷前方是否有車。路中儲存著汽車的集合,顯然路上就應該有增加車輛     和減少車輛的方法了。

   我們要捕捉路上減少一輛車的過程,所以,這個車並不需要單獨設計成為一個物件。用一個字串表示就行了。



三.開發過程
     

  類的編寫:

  Road類的編寫:

  每個Road物件都有一個name成員變數來代表方向,有一個vehicles成員變數來代表方向上的車輛集合。

  在Road物件的構造方法中啟動一個執行緒每隔一個隨機的時間向vehicles集合中增加一輛車(用一個“路線名_id”形   式的字串進行表示)。

  在Road物件的構造方法中啟動一個定時器,每隔一秒檢查該方向上的燈是否為綠,是則列印車輛集合和將集合     中的第一輛車移除掉。

  程式碼如下:

  1. <span style=
    "font-size:18px;">     
  2. publicclass Road {  
  3.  private List<String> vechicles = new ArrayList<String>();  
  4.  private String name = null;  
  5.  public Road(String name) {  
  6.   this.name = name;  
  7.   // 建立車輛
  8.   ExecutorService pool = Executors.newSingleThreadExecutor();   //執行緒池
  9.   pool.execute(new Runnable() {  
  10.    @Override
  11.    publicvoid run() {  
  12.     // TODO Auto-generated method stub
  13.     for (int i = 1; i < 1000; i++) {  
  14.      try {  
  15.       // 隨機獲取1-10秒的數,讓車輛不定時的往裡增加
  16.       Thread.sleep((new Random().nextInt(10) + 1) * 1000);  
  17.      } catch (InterruptedException e) {  
  18.       // TODO Auto-generated catch block
  19.       e.printStackTrace();  
  20.      }  
  21.      vechicles.add(Road.this.name + "_" + i);  
  22.     }  
  23.    }  
  24.   });  
  25.   //建立一個執行緒,按時間安排執行任務的功能
  26.   ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  
  27.   timer.scheduleAtFixedRate(new Runnable() {  
  28.    @Override
  29.    publicvoid run() {  
  30.     // TODO Auto-generated method stub
  31.     if (vechicles.size() > 0// 判斷現在是否有車輛
  32.     {  
  33.      boolean lighted = Lamp.valueOf(Road.this.name).isLight();  
  34.      //System.out.println(Road.this.name+">>>>>>>>>>>>>"+lighted);
  35.      if (lighted) {  
  36.       System.out  
  37.         .println(vechicles.remove(0) + " ...is traverse");  
  38.      }  
  39.     }  
  40.    }  
  41.   }, 11, TimeUnit.SECONDS);  
  42.  }  
  43. }</span>  

  Lamp燈的編寫:

  Lamp類來表示一個交通燈,12個,使用列舉。

   系統中有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:18px;">     
  2. publicclass Road {  
  3.  private List<String> vechicles = new ArrayList<String>();  
  4.  private String name = null;  
  5.  public Road(String name) {  
  6.   this.name = name;  
  7.   // 建立車輛
  8.   ExecutorService pool = Executors.newSingleThreadExecutor();   //執行緒池
  9.   pool.execute(new Runnable() {  
  10.    @Override
  11.    publicvoid run() {  
  12.     // TODO Auto-generated method stub
  13.     for (int i = 1; i < 1000; i++) {  
  14.      try {  
  15.       // 隨機獲取1-10秒的數,讓車輛不定時的往裡增加
  16.       Thread.sleep((new Random().nextInt(10) + 1) * 1000);  
  17.      } catch (InterruptedException e) {  
  18.       // TODO Auto-generated catch block
  19.       e.printStackTrace();  
  20.      }  
  21.      vechicles.add(Road.this.name + "_" + i);  
  22.     }  
  23.    }  
  24.   });  
  25.   //建立一個執行緒,按時間安排執行任務的功能
  26.   ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  
  27.   timer.scheduleAtFixedRate(new Runnable() {  
  28.    @Override
  29.    publicvoid run() {  
  30.     // TODO Auto-generated method stub
  31.     if (vechicles.size() > 0// 判斷現在是否有車輛
  32.     {  
  33.      boolean lighted = Lamp.valueOf(Road.this.name).isLight();  
  34.      //System.out.println(Road.this.name+">>>>>>>>>>>>>"+lighted);
  35.      if (lighted) {  
  36.       System.out  
  37.         .println(vechicles.remove(0) + " ...is traverse");  
  38.      }  
  39.     }  
  40.    }  
  41.   }, 11, TimeUnit.SECONDS);  
  42.  }  
  43. }</span>  

 LampController類的編寫:

 整個系統中只能有一套交通燈控制系統,所以,LampController類最好是設計成單例。

 LampController構造方法中要設定第一個為綠的燈。

 LampController物件的start方法中將當前燈變綠,然後啟動一個定時器,每隔10秒將當前燈變紅和將下一個燈變  綠。

  1. <span style="font-size:18px;">  程式碼如下:  
  2.  publicclass LampController {  
  3.  private Lamp controlLamp;  
  4.  public LampController() {  
  5.   controlLamp = Lamp.S2N;  //先初始化一條線路上的燈
  6.   controlLamp.light();  
  7.   // TODO Auto-generated constructor stub
  8.   ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  
  9.   timer.scheduleWithFixedDelay(  
  10.     new Runnable() {  
  11.      @Override
  12.      publicvoid run() {  
  13.       // TODO Auto-generated method stub
  14.       controlLamp = controlLamp.blackOut();  
  15.      }  
  16.     },    
  17.     10,   
  18.     10,   
  19.     TimeUnit.SECONDS);  
  20.  }  
  21. }  
  22.   MainClass類的編寫  
  23.   用for迴圈創建出代表12條路線的物件。  
  24.   接著再獲得LampController物件並呼叫其start方法。  
  25.   程式碼如下:  
  26.  publicclass MainClass {  
  27.  /** 
  28.   * @param args 
  29.   */
  30.  publicstaticvoid main(String[] args) {  
  31.   // TODO Auto-generated method stub
  32.   String[] directions = new String[] { "S2N""S2W""E2W""E2S""N2S",  
  33.     "N2E""W2E""W2N""S2E""E2N""N2W""W2S" };  
  34.   for (int i  = 0; i < directions.length; i++) {  
  35.    new Road(directions[i]);  
  36.   }  
  37.   new LampController();  
  38. }  
  39. }</span>  

注:面向物件的思路要清晰:誰擁有資料,誰就提供這些資料的方法。例子:人開門,人在黑板上畫圓, 司機剎車。