一、面向對象分析
根據項目的需求,爲了更加直觀的瞭解需求,設計程序,我們畫出交通燈管理系統的路線圖如下:
根據此圖可以清楚的看出如下內容:
1、 在一個典型的十字路口總共可以通行的線路共有12條;
2、 12條線路相應的也應該對應12盞路燈,但根據常識可以知道在十字路口向右轉彎是不需要路燈及等待的,但爲了統一的管理我們也假象分別對應一盞常綠的路燈。
3、 經過上面的分析我們發現現在真正需要我們用心思考的只剩下了8條線路。
4、 爲了更加方便的講述這12條線路,我們按照它們行駛的方向分別起名爲:
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"。
5、 再經過更深入一些的分析我們發現,圖中用相同顏色畫出的路線存在着一一對應的關係,即:雙方的阻塞與通行將永遠保持一致!
6、 所以,剩下的8條線路將又被簡化爲4條線路——"S2N","S2W","E2W","E2S",我們只要控制好這四條線路,當這四條線路的狀態發生變化時,只要通知其對應的線路即可保證交通的順利運行。
7、 接着我們要開始更進一步的研究——根據日常生活的常識我們發現,剩下的這四條線路當其中的一條處於通行狀態時,其它三條絕對處於阻塞狀態,所以它們四者之間存在着一個挨着一個線性關係:這就是這4條線路必須循環着通行,此路通行的時間消耗完畢之後,緊接其後的另一條纔可通車。
8、 爲了更好表示以上分析的結果,我們畫出示意圖如下:
9、所以我們只要按照上面的方式安裝交通燈:讓S2N路上的交通燈和N2S路上的交通燈保持一致,同時S2N上的交通燈變紅後才允許S2W上面的燈變綠,如此循環,則可以很輕鬆的實現交通燈管理系統的基本功能。
二、面向對象設計
根據分析可以發現,此係統涉及到的對象有如下幾個:
1)道路
2)交通燈
3)交通燈控制器
)車輛
通過對各個對象的分析可以發現,“車輛”這一對象並沒有涉及到具體的行駛問題,所以可以只用一個名字來區分即可。
各類的大概設計如下:
1、Road類的設計
Ø 設計一個Road類來表示路線,每個Road對象代表一條路線,總共有12條路線,即系統中總共要產生12個Road實例對象。
Ø 每條路線上隨機增加新的車輛,增加到一個集合中保存。
Ø 每條路線每隔一秒都會檢查控制本路線的燈是否爲綠,是則將本路線保存車的集合中的第一輛車移除,即表示車穿過了路口。
2、Lamp類的設計
Ø 設計一個Lamp類來表示一個交通燈,每個交通燈都維護一個狀態:亮(綠)或不亮(紅),每個交通燈要有變亮和變黑的方法,並且能返回自己的亮黑狀態。
Ø 總共有12條路線,所以,系統中總共要產生12個交通燈。右拐彎的路線本來不受燈的控制,但是爲了讓程序採用統一的處理方式,故假設出有四個右拐彎的燈,只是這些燈爲常亮狀態,即永遠不變黑。
Ø 除了右拐彎方向的其他8條路線的燈,它們是兩兩成對的,可以歸爲4組,所以,在編程處理時,只要從這4組中各取出一個燈,對這4個燈依次輪詢變亮,與這4個燈方向對應的燈則隨之一同變化,因此Lamp類中要有一個變量來記住自己相反方向的燈,在一個Lamp對象的變亮和變黑方法中,將對應方向的燈也變亮和變黑。每個燈變黑時,都伴隨者下一個燈的變亮,Lamp類中還用一個變量來記住自己的下一個燈。
Ø 無論在程序的什麼地方去獲得某個方向的燈時,每次獲得的都是同一個實例對象,所以Lamp類改用枚舉來做顯然具有很大的方便性,永遠都只有代表12個方向的燈的實例對象。
3、控制器的設計
Ø 設計一個LampController類,它定時讓當前的綠燈變紅即可。
三、編碼實現
1、Road類的實現
public class Road {
private List<String> vechicles = new ArrayList<String>();
private String name =null;
public Road(String name){
this.name = name;
//模擬車輛不斷隨機上路的過程
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(new Runnable(){
public void run(){
for(int i=1;i<1000;i++){
try {
Thread.sleep((new Random().nextInt(10) + 1) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
vechicles.add(Road.this.name + "_" + i);
}
}
});
//每隔一秒檢查對應的燈是否爲綠,是則放行一輛車
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run(){
if(vechicles.size()>0){
boolean lighted = Lamp.valueOf(Road.this.name).isLighted();
if(lighted){
System.out.println(vechicles.remove(0) + " is traversing !");
}
}
}
},
1,
1,
TimeUnit.SECONDS);
}
}
2、Lamp類的實現
public enum Lamp {
/*每個枚舉元素各表示一個方向的控制燈*/
S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false),
/*下面元素表示與上面的元素的相反方向的燈,它們的“相反方向燈”和“下一個燈”應忽略不計!*/
N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false),
/*由南向東和由西向北等右拐彎的燈不受紅綠燈的控制,所以,可以假想它們總是綠燈*/
S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true);
private Lamp(String opposite,String next,boolean lighted){
this.opposite = opposite;
this.next = next;
this.lighted = lighted;
}
/*當前燈是否爲綠*/
private boolean lighted;
/*與當前燈同時爲綠的對應方向*/
private String opposite;
/*當前燈變紅時下一個變綠的燈*/
private String next;
public boolean isLighted(){
return lighted;
}
/**
* 某個燈變綠時,它對應方向的燈也要變綠
*/
public void light(){
this.lighted = true;
if(opposite != null){
Lamp.valueOf(opposite).light();
}
System.out.println(name() + " lamp is green,下面總共應該有6個方向能看到汽車穿過!");
}
/**
* 某個燈變紅時,對應方向的燈也要變紅,並且下一個方向的燈要變綠
* @return 下一個要變綠的燈
*/
public Lamp blackOut(){
this.lighted = false;
if(opposite != null){
Lamp.valueOf(opposite).blackOut();
}
Lamp nextLamp= null;
if(next != null){
nextLamp = Lamp.valueOf(next);
System.out.println("綠燈從" + name() + "-------->切換爲" + next);
nextLamp.light();
}
return nextLamp;
}
}
3、LampController類的實現
public class LampController {
private Lamp currentLamp;
public LampController(){
//剛開始讓由南向北的燈變綠;
currentLamp = Lamp.S2N;
currentLamp.light();
/*每隔10秒將當前綠燈變爲紅燈,並讓下一個方向的燈變綠*/
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run(){
System.out.println("來啊");
currentLamp = currentLamp.blackOut();
}
},
10,
10,
TimeUnit.SECONDS);
}
}
4、主函數的實現
public class MainClass {
/**
* @param args
*/
public static void main(String[] args) {
/*產生12個方向的路線*/
String [] directions = new String[]{
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"
};
for(int i=0;i<directions.length;i++){
new Road(directions[i]);
}
/*產生整個交通燈系統*/
new LampController();
}
}
四、系統測試
系統運行後根據控制檯輸出的提示信息基本上確定此程序沒有什麼大的錯誤,但並沒有用具體的黑盒測試、白盒測試或者專業的自動化測試工具進行專業的測試,所以程序中還可能存在一些未知的安全隱患,具體使用時還需小心。