天天看點

黑馬程式員--java技術--交通燈管理系統

  •   ------- android教育訓練、java教育訓練、期待與您交流! ----------

1.交通燈管理系統的項目需求

  • 異步随機生成按照各個路線行駛的車輛
  • 信号燈忽略黃燈,隻考慮紅燈與綠燈
  • 應考慮左轉車輛控制信号燈,右轉車輛不受信号燈控制。
  • 具體信号燈控制邏輯與現實生活中普通交通燈控制邏輯相同,不考慮特殊情況下的控制邏輯。注:南北向車輛與東西車輛交替放行,同向先放直再放左。
  • 每輛車通過路口時間為1s(提示:可通過線程Sleep的方式模拟)
  • 随機生成車輛時間間隔以及紅綠燈交換時間間隔自定,可以設定
  • 不要求實作GUI,隻考慮系統邏輯實作,可通過Log方式展現程式運作結果
  • 黑馬程式員--java技術--交通燈管理系統
  • 一、面向對象的分析與設計

    1、每條路線上都會出現多輛車,路線上要随機增加新的車,在燈綠期間還要每秒鐘減少一輛車。

    1.設計一個Road類來表示路線,每個Road對象代表一條路線,總共有12條路線,即系統中總共要産生12個Road執行個體對象。

    2.每條路線上随機增加新的車輛,增加到一個集合中儲存。

    3.每條路線每隔一秒都會檢查控制本路線的燈是否為綠,是則将本路線儲存車的集合中的第一輛車移除,即表示車穿過了路口。

    2、每條路線每隔一秒都會檢查控制本路線的燈是否為綠,一個燈由綠變紅時,應該将下一個方向的燈變綠。

    1.設計一個Lamp類來表示一個交通燈,每個交通燈都維護一個狀态:亮(綠)或不亮(紅),每個交通燈要有變亮和變黑的方法,并且能傳回自己的亮黑狀态。

    2.總共有12條路線,是以,系統中總共要産生12個交通燈。右拐彎的路線本來不受燈的控制,但是為了讓程式采用統一的處理方式,故假設出有四個右拐彎的燈,隻是這些燈為常亮狀态,即永遠不變黑。

    3.除了右拐彎方向的其他8條路線的燈,它們是兩兩成對的,可以歸為4組,是以,在程式設計處理時,隻要從這4組中各取出一個燈,對這4個燈依次輪詢變亮,與這4個燈方向對應的燈則随之一同變化,是以Lamp類中要有一個變量來記住自己相反方向的燈,在一個Lamp對象的變亮和變黑方法中,将對應方向的燈也變亮和變黑。每個燈變黑時,都伴随者下一個燈的變亮,Lamp類中還用一個變量來記住自己的下一個燈。

    4.無論在程式的什麼地方去獲得某個方向的燈時,每次獲得的都是同一個執行個體對象,是以Lamp類改用枚舉來做顯然具有很大的友善性,永遠都隻有代表12個方向的燈的執行個體對象。

    5.設計一個LampController類,它定時讓目前的綠燈變紅。

    二、Road類的編寫

    1、每個Road對象都有一個name成員變量來代表方向,有一個vehicles成員變量來代表方向上的車輛集合。

    2、在Road對象的構造方法中啟動一個線程每隔一個随機的時間向vehicles集合中增加一輛車(用一個“路線名_id”形式的字元串進行表示)。

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

    三、Lamp類的編寫

    1、系統中有12個方向上的燈,在程式的其他地方要根據燈的名稱就可以獲得對應的燈的執行個體對象,綜合這些因素,将Lamp類用java5中的枚舉形式定義更為簡單。

    2、每個Lamp對象中的亮黑狀态用lighted變量表示,選用S2N、S2W、E2W、E2N這四個方向上的Lamp對象依次輪詢變亮,Lamp對象中還要有一個oppositeLampName變量來表示它們相反方向的燈,再用一個nextLampName變量來表示此燈變亮後的下一個變亮的燈。這三個變量用構造方法的形式進行指派,因為枚舉元素必須在定義之後引用,是以無法再構造方法中彼此互相引用,是以,相反方向和下一個方向的燈用字元串形式表示。

    3、增加讓Lamp變亮和變黑的方法:light和blackOut,對于S2N、S2W、E2W、E2N這四個方向上的Lamp對象,這兩個方法内部要讓相反方向的燈随之變亮和變黑,blackOut方法還要讓下一個燈變亮。

    4、除了S2N、S2W、E2W、E2N這四個方向上的Lamp對象之外,其他方向上的Lamp對象的nextLampName和oppositeLampName屬性設定為null即可,并且S2N、S2W、E2W、E2N這四個方向上的Lamp對象的nextLampName和oppositeLampName屬性必須設定為null,以便防止light和blackOut進入死循環。

    四、LampController類的編寫

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

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

    3、LampController對象的start方法中将目前燈變綠,然後啟動一個定時器,每隔10秒将目前燈變紅和将下一個燈變綠。

    五、MainClass類的編寫

    1、用for循環建立出代表12條路線的對象。

    2、接着再獲得LampController對象并調用其start方法。

代碼:

1.Lamp.java(這裡用了枚舉,總的十二個燈)  

[java]  view plain copy

  1. public enum Lamp {  
  2.  //通過對交通燈問題的分析,一共十二條路線通過枚舉的方法将每條線路都标注出來  
  3.     //但隻需考慮四個路線即可  
  4. S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false),  
  5. N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false),  
  6. S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true);  
  7.  private Lamp(){} //枚舉的構造方法必須是私有的,必須有一個無參構造方法  
  8.  //opposite是指對面的燈,next是指下一個燈  
  9.  private Lamp(String opposite,String next,boolean lighted){  
  10.     this.opposite = opposite;  
  11.     this.next = next;  
  12.     this.lighted = lighted;  
  13.  }  
  14.  private boolean lighted;//定一個燈亮或不亮的變量  
  15.  private String opposite;//對應燈  
  16.  private String next;   //下個燈  
  17.  public boolean isLighted(){//燈是否亮的方法  
  18.     return lighted;  
  19.  }  
  20.  public void light(){ //定義一個讓燈變綠的方法  
  21.     this.lighted =true;  
  22.     if(opposite !=null){//對應的燈的方法  
  23.        Lamp.valueOf(opposite).light();  
  24.     }  
  25.     System.out.println(name() + " lamp is green, 下面總共應該有6個方向能看到汽車穿過");  
  26.  }  
  27.  //在定義一個讓燈變紅的方法  
  28.  public Lamp blackOut(){  
  29.     this.lighted =false;  
  30.     if(opposite !=null){  
  31.        Lamp.valueOf(opposite).blackOut();  
  32.     }  
  33.     //初始化下一個燈的狀态  
  34.     Lamp nextLamp = null;  
  35.     //如果下一個燈不為空的時候  
  36.     if(next !=null){  
  37.        nextLamp = Lamp.valueOf(next);  
  38.        System.out.println("綠燈從" + name() +"------------>切換為" +next);  
  39.        nextLamp.light();  
  40.     }  
  41.     return nextLamp;  
  42.  }  
  43. }  

2.Road.java

[java]  view plain copy

  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3. import java.util.Random;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.Executors;  
  6. import java.util.concurrent.ScheduledExecutorService;  
  7. import java.util.concurrent.TimeUnit;  
  8. public class Road {//建立容量,用于存儲各種類型的車輛  
  9.    //用List類型,是為了面向接口程式設計  
  10.    private List<String> vechicles = new ArrayList<String>();  
  11.    //由于每條路線上有不同的車,且每輛車也有不同的名字,是以這裡需要定義車的名字和每條路的方法也就是說每建立一條路就會有一個路的名字  
  12.    private String name = null;  
  13.    public Road(String name){  
  14.       this.name = name;  
  15.       //建立一個線程執行池,利用線程池建立一個線程  
  16.       ExecutorService pool = Executors.newSingleThreadExecutor();  
  17.       pool.execute(new Runnable(){  
  18.          public void run(){  
  19.             //假設每1秒鐘路上就會出現一輛車,定義一個方法,假設總共有999輛車  
  20.             for(int i=1; i<1000;i++){  
  21.                try {  
  22.                   //為了讓程式更為嚴謹,這裡可以讓随機産生車的時間改為1到10秒内随機生成  
  23.                   Thread.sleep((new Random().nextInt(10) + 1) * 1000);  
  24.                } catch (InterruptedException e) {  
  25.                   e.printStackTrace();  
  26.                }  
  27.                //傳回外部類的成員變量需要外部類名.this.name  
  28.                vechicles.add(Road.this.name +"_" + i);  
  29.             }  
  30.          }  
  31.       });  
  32.       //建立一個多線程中的定時器  
  33.       ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  
  34.       timer.scheduleAtFixedRate(  
  35.             new Runnable(){  
  36.                public void run(){  
  37.                   //将集合中的第一輛車移除,但前提是判斷路上有沒有車  
  38.                   if(vechicles.size() > 0){  
  39.                      //定義一個标簽,用于記錄交通燈的紅綠燈現象,擷取目前的燈是什麼狀态  
  40.                      boolean ligthed = Lamp.valueOf(Road.this.name).isLighted();  
  41.                      if(ligthed){  
  42.                         System.out.println(vechicles.remove(0) +" is traversing!");  
  43.                      }  
  44.                   }  
  45.                }  
  46.             },  
  47.             1, //多久之後執行  
  48.             1, //再過多久執行,頻率  
  49.             TimeUnit.SECONDS);//機關  
  50.    }  
  51. }  

3、LampController.java

[java]  view plain copy

  1. package com.itheima.interview.traffic;  
  2. import java.util.concurrent.Executors;  
  3. import java.util.concurrent.ScheduledExecutorService;  
  4. import java.util.concurrent.TimeUnit;  
  5. //建立一個交通燈的控制器LampController  
  6. public class LampController {  
  7.    //定義一個變量,用于記錄目前燈的狀态  
  8.    private Lamp currentLamp;  
  9.    //定義這個控制器的構造方法  
  10.    public LampController(){  
  11.       //首先讓目前的燈記錄第一條道路上的紅綠燈情況  
  12.       currentLamp = Lamp.S2N;  
  13.       currentLamp.light();  
  14.       //定義一個定時器,用于控制交通燈的紅綠燈跳轉時間  
  15.       ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  
  16.       timer.scheduleAtFixedRate(  
  17.             new Runnable(){  
  18.                public void run(){  
  19.                   //每過10秒就要将目前的燈變換成下一個燈  
  20.                   //System.out.println("來啦");  
  21.                   currentLamp =currentLamp.blackOut();  
  22.                }  
  23.             },  
  24.             2,  
  25.             2,  
  26.             TimeUnit.SECONDS);  
  27.    }  
  28. }  

4、主函數MainClass.java

[java]  view plain copy

  1. package com.itheima.interview.traffic;  
  2. public class MainClass {  
  3.    public static void main(String[] args) {  
  4.       //為了建立十二條路線,這裡不可能将每條都直接寫出來,是以就用到了容器和循環  
  5.       String[] direction = new String[]{"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};  
  6.       for(int i=0; i<direction.length; i++){  
  7.          new Road(direction[i]);  
  8.       }  
  9.       //建立一個控制器LampController  
  10.       new LampController();  
  11.    }  
  12. }  

總結:“誰擁有資料,誰就對外提供操作這些資料的方法!”做面對對象應該熟記的一句話,

雖然代碼很短,看得懂了,但讓我獨立操作,還是太難了。

繼續閱讀