黑馬程式設計師 7K面試題破解:交通燈管理系統
----------------------
ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------
交通燈管理系統
使用者需求
模擬實現十字路口的交通燈管理系統邏輯,具體需求如下:
非同步隨機生成按照各個路線行駛的車輛。
例如:
由南向而來去往北向的車輛 ---- 直行車輛
由西向而來去往南向的車輛 ---- 右轉車輛
由東向而來去往南向的車輛 ---- 左轉車輛
。。。
訊號燈忽略黃燈,只考慮紅燈和綠燈。
應考慮左轉車輛控制訊號燈,右轉車輛不受訊號燈控制。
具體訊號燈控制邏輯與現實生活中普通交通燈控制邏輯相同,不考慮特殊情況下的控制邏輯。
注:南北向車輛與東西向車輛交替放行,同方向等待車輛應先放行直行車輛而後放行左轉車輛。
每輛車通過路口時間為1秒(提示:可通過執行緒Sleep的方式模擬)。
隨機生成車輛時間間隔以及紅綠燈交換時間間隔自定,可以設定。
不要求實現GUI,只考慮系統邏輯實現,可通過Log方式展現程式執行結果。
需求分析
圖解說明
文字說明
(1)這裡總共有12條路線,每條路線作為一個物件存在。
(2)作為程式設計模型,可假設每條線路都有一個紅綠燈,對其控制。
(3)其中右轉彎的4條路線的控制燈可以假設為常綠狀態。
(4)另外的八條線路是兩兩成對的,就可以歸為4組,程式只需考慮圖中標註了數字的4條路線的控制燈的切換順序即可,這4條路線的對應的反向的控制燈是隨著這4條路線進行相同切換的。
概要設計
涉及到的物件:紅綠燈、紅綠燈控制系統、汽車和路線。
1、對路線和車兩個物件的分析:
路擁有車輛這個資料,路本身知道自己身上有幾輛車,所以,路作為一個集合,有增加和刪除物件(車)的方法,這樣就可以將車和路線繫結在一起。
1)設計一個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、可以將每條路線看作一個物件,就有12個Road的例項物件。
2、每條路線上都有有車,應該隨機產生新的車輛,將產生的車輛儲存到路內部的一個集合中。在Road物件的構造方法中啟動一個執行緒每隔一個隨機的時間向vehicles集合中增加一輛車(用一個“路線名_id”形式的字串進行表示)。
3、路要以燈為標準,判斷是否燈是亮的,在燈亮的時間內,才能讓車行駛,即移除路面上的第一輛車。
4、移除車輛的操作,要用到定時器,並每隔一秒檢查該方向上燈是否為綠,是則在相應的時間內移除第一輛車,使用scheduleAtFixedRate方法。
Lamp類的編寫
分析:
1、總共有12條路線,有12個方向,就需要定義12燈,用列舉類建立燈物件
2、12個燈分別如程式碼中所示
3、12個燈中,有四個右轉的等可設為常亮狀態,即S2E,E2N,N2W,W2S
4、對於剩下的燈,可分為4組,每組的兩個燈是對應的,這裡設定當前燈和對應燈,
5、對應的兩個燈是同時亮的,而與其垂直方向的燈則不能亮。如南北方向燈亮,東西方向則不亮
6、當前燈亮時,就要設定對應燈為亮,並設定垂直方向燈為不亮
LampContriller類的編寫
分析:交通燈控制器
1、最開始有個當前燈作為第一個燈執行
2、在構造方法中,
要指定當前燈為綠狀態,以S2N作為第一個
建立一個定時器,每隔十秒,讓當前燈變紅,讓下一個方向(垂直方向)的燈變綠
測試類的編寫
測試:
1、建立12條路線,即12個物件
2、執行交通燈控制器系統LampController
擴充套件工具類
本類純屬自己擴充:
因為本人英語不是很好,看程式各個線路和執行結果各個線路很是費時,所以為了程式結果在這具有更好的可讀性,編寫此類。
SwitchLamp工具類,提供一個方法,把燈,路的英文縮寫,轉換成中文。
編碼
Road類----------路類
/*
* 每個Road物件代表一條路線,總共有12條路線,即系統中總共要產生12個Road例項物件。
* 每條路線上隨機增加新的車輛,增加到一個集合中儲存。
* 每條路線每隔一秒都會檢查控制本路線的燈是否為綠,是則將本路線儲存車的集合中的第一輛車移除,即表示車穿過了路口。
*/
public class Road {
// 車輛集合
private List<String> vechicles = new ArrayList<String>();
// 每條路線的名字
private String name = null;
public Road(final String name) {
this.name = name;
// 模擬車輛不斷隨機上路的過程
// public static ExecutorService newSingleThreadExecutor()
// 建立一個使用單個 worker 執行緒的 Executor,以無界佇列方式來執行該執行緒。
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 1; i < 1000; i++) {
try {
// 讓執行緒睡眠,時間隨機生成為1-10秒
Thread.sleep((new Random().nextInt(10) + 1) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//vechicles.add(Road.this.name + "_" + i);
//呼叫SwitchLamp類的靜態方法convert()把英文名改成中文名
vechicles.add(SwitchLamp.convert(Road.this.name) + "_" + i);
}
}
});
// 每隔一秒檢查對應的燈是否為綠,是則放行一輛車
// public static ScheduledExecutorService newScheduledThreadPool(int
// corePoolSize)
// 建立一個執行緒池,它可安排在給定延遲後執行命令或者定期地執行。
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
// ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
// 建立並執行一個在給定初始延遲後首次啟用的定期操作,後續操作具有給定的週期
// command---要執行的執行緒
// initialDelay---首次執行的延遲時間
// period---連續執行之間的週期,多少單位以後再執行
// unit---initialDelay和period引數的時間單位,毫秒,秒,分還是什麼?
timer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
if (vechicles.size() > 0) {
//獲取這條路線的燈物件,再判斷這個燈是否為綠色
//內部類要用到外部類的成員變數外部類名.this.成員變數名
boolean lighted = Lamp.valueOf(Road.this.name).isLighted();
//boolean lighted = Lamp.valueOf(SwitchLamp.convert(Road.this.name)).isLighted();
//假如綠燈是亮的,則放行一輛車,把這個車在集合中刪除,並輸出
if(lighted){
System.out.println(vechicles.remove(0)+"車通過!");
}
}
}
},
1,// 1單位後開始執行
1,// 每過1單位後執行一次
TimeUnit.SECONDS);// 單位:秒
}
}
Lamp類----------交通燈類
/**
* Lamp 燈類
*
* 每個Lamp元素代表一個方向的燈,總共有12個方向,所以總共有12個Lamp元素。
* 以下字母代表方向:
* N------North------北
* S------South------南
* W------West-------西
* E------East-------東
*
* 有如下一些方向的燈,每兩個形成一組,一組燈同時變綠或變紅,所以,
* 程式程式碼只需要控制每組燈中的一個燈即可:
*
* S2N,N2S------南到北,北到南
* S2W,N2E------南到西,北到東
* E2W,W2E------東到西,西到東
* E2S,W2N------東到南,西到北
* S2E,N2W------南到東,北到西
* E2N,W2S------東到北,西到南
* 上面最後兩行的燈是虛擬的,由於從南到東和從西向北,以及它們的對應方向不受紅綠燈的控制,
* 所以,可以假想它們總是綠燈。
*
* @author 小小灬程式猿
*/
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() {
}
// 構造方法:於當前燈同時為綠的方向,下一個變綠的燈,當前燈是否為綠
private Lamp(String opposite, String next, boolean lighted) {
this.opposite = opposite;
this.next = next;
this.lighted = lighted;
}
// 與當前燈同時為綠的對應方向
private String opposite;
// 當前燈變紅時下一個變綠的燈
private String next;
// 當前燈是否為綠
private boolean lighted;
/**
* 判斷當前燈是否變綠
*/
public boolean isLighted() {
return lighted;
}
/**
* 把某個燈變綠時,它對應方向的燈也要變綠
*/
public void light(){
//把某個變綠
this.lighted=true;
//對應的燈如果不為空,也要變綠
if(opposite !=null){
Lamp.valueOf(opposite).light();
}
//呼叫SwitchLamp類的靜態方法convert()把英文名改成中文名
System.out.println(SwitchLamp.convert(name())+"路交通燈變綠!");
}
/**
* 某個燈變紅時,對應方向的燈也要變紅,並且下一個方向的燈要變綠
* @return 下一個要變綠的燈
*/
public Lamp blackOut(){
//把當前燈變紅
this.lighted=false;
//如果對應的燈不是空的話,也把它的燈變紅
if(opposite!=null){
Lamp.valueOf(opposite).blackOut();
}
//下一個要變綠的燈
Lamp nextLamp = null;
//下一個燈如果不為空的話
if(next != null){
//先獲取下一個燈的物件
nextLamp = Lamp.valueOf(next);
//列印到控制檯
//呼叫SwitchLamp類的靜態方法convert()把英文名改成中文名
System.out.println("綠燈從"+SwitchLamp.convert(name())+"-------->切換為" + SwitchLamp.convert(next));
//把下一個燈變綠
nextLamp.light();
}
return nextLamp;
}
}
LampContriller類---------交通燈控制系統類
/**
* 交通燈控制系統
* @author 小小灬程式猿
*
*/
public class LampController {
private Lamp currentLamp;
public LampController(){
//剛開始讓由南向北的燈變綠
//獲取到由南向北的燈物件
currentLamp=Lamp.S2N;
//把這個燈變綠
currentLamp.light();
//每隔10秒將當前綠燈變為紅燈,並讓下一個方向的燈變綠
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
currentLamp =currentLamp.blackOut();
}
},
10,
10,
TimeUnit.SECONDS);
}
}
SwitchLamp類-----------工具類
/**
* 工具類,用來把傳過來哪路到哪路的英文,變為中文
*
* @author 小小灬程式猿
*
*/
public class SwitchLamp {
// 因為工具類,所以構造方法私有
private SwitchLamp() {
}
/**
* 根據傳來的路的英文名字,返回路的中文名字
*
* @param 路英文名字
* @return 路中文名字
*/
public static String convert(String name) {
// 1.7新特性switch可以是字串
// 由於我的myeclipse設定不了編譯器7.0所以只能用下面的,建議使用switch
// switch(name){
// }
String temp = null;
if (name.equals("S2N")) {
temp = "南到北";
} else if (name.equals("S2W")) {
temp = "南到西";
} else if (name.equals("S2E")) {
temp = "南到東";
} else if (name.equals("N2S")) {
temp = "北到南";
} else if (name.equals("N2E")) {
temp = "北到東";
} else if (name.equals("N2W")) {
temp = "北到西";
} else if (name.equals("E2W")) {
temp = "東到西";
} else if (name.equals("E2S")) {
temp = "東到南";
} else if (name.equals("E2N")) {
temp = "東到北";
} else if (name.equals("W2E")) {
temp = "西到東";
} else if (name.equals("W2N")) {
temp = "西到北";
} else if (name.equals("W2S")) {
temp = "西到南";
}
return temp;
}
}
MainClass類-----------測試類
public class MainClass {
public static void main(String[] args) {
//產生12個方向的路線
String[] directions = new String[]{
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"
};
for(String road : directions){
new Road(road);
}
//啟動整個交通燈系統
new LampController();
}
}
測試:
圖示:
說明 :
每次一個燈變綠,對應的一個燈也變綠,還有四個向右轉彎的燈,所以每次最多有6個路的車通過,
可以少於6個,因為這條路可能沒有車,通過檢視,比較,發現沒有錯誤。
----------------------
ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------